Merge misc patches from Andrew Morton: - Florian has vanished so I appear to have become fbdev maintainer again :( - Joel and Mark are distracted to welcome to the new OCFS2 maintainer - The backlight queue - Small core kernel changes - lib/ updates - The rtc queue - Various random bits * akpm: (164 commits) rtc: rtc-davinci: use devm_*() functions rtc: rtc-max8997: use devm_request_threaded_irq() rtc: rtc-max8907: use devm_request_threaded_irq() rtc: rtc-da9052: use devm_request_threaded_irq() rtc: rtc-wm831x: use devm_request_threaded_irq() rtc: rtc-tps80031: use devm_request_threaded_irq() rtc: rtc-lp8788: use devm_request_threaded_irq() rtc: rtc-coh901331: use devm_clk_get() rtc: rtc-vt8500: use devm_*() functions rtc: rtc-tps6586x: use devm_request_threaded_irq() rtc: rtc-imxdi: use devm_clk_get() rtc: rtc-cmos: use dev_warn()/dev_dbg() instead of printk()/pr_debug() rtc: rtc-pcf8583: use dev_warn() instead of printk() rtc: rtc-sun4v: use pr_warn() instead of printk() rtc: rtc-vr41xx: use dev_info() instead of printk() rtc: rtc-rs5c313: use pr_err() instead of printk() rtc: rtc-at91rm9200: use dev_dbg()/dev_err() instead of printk()/pr_debug() rtc: rtc-rs5c372: use dev_dbg()/dev_warn() instead of printk()/pr_debug() rtc: rtc-ds2404: use dev_err() instead of printk() rtc: rtc-efi: use dev_err()/dev_warn()/pr_err() instead of printk() ...
Unified · Split
| @@ -48,3 +48,8 @@ max_ratio (read-write) · 47 unmodified lines | ||
| 48 | 48 | most of the write-back cache. For example in case of an NFS |
| 49 | 49 | mount that is prone to get stuck, or a FUSE mount which cannot |
| 50 | 50 | be trusted to play fair. |
| 51 | + | |
| 52 | +stable_pages_required (read-only) | |
| 53 | + | |
| 54 | + If set, the backing device requires that all pages comprising a write | |
| 55 | + request must not be changed until writeout is complete. | |
| @@ -4,7 +4,7 @@ Kernel driver lp855x · 3 unmodified lines | ||
| 4 | 4 | Backlight driver for LP855x ICs |
| 5 | 5 | |
| 6 | 6 | Supported chips: |
| 7 | − Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556 | |
| 7 | + Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557 | |
| 8 | 8 | |
| 9 | 9 | Author: Milo(Woogyom) Kim <milo.kim@ti.com> |
| 10 | 10 | |
| @@ -24,7 +24,7 @@ Value : pwm based or register based · 13 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | 2) chip_id |
| 26 | 26 | The lp855x chip id. |
| 27 | −Value : lp8550/lp8551/lp8552/lp8553/lp8556 | |
| 27 | +Value : lp8550/lp8551/lp8552/lp8553/lp8556/lp8557 | |
| 28 | 28 | |
| 29 | 29 | Platform data for lp855x |
| 30 | 30 | ------------------------ |
| @@ -1228,7 +1228,7 @@ hierarchy and routing of interrupts in the hardware. · 1227 unmodified lines | ||
| 1228 | 1228 | The interrupt tree model is fully described in the |
| 1229 | 1229 | document "Open Firmware Recommended Practice: Interrupt |
| 1230 | 1230 | Mapping Version 0.9". The document is available at: |
| 1231 | −<http://playground.sun.com/1275/practice>. | |
| 1231 | +<http://www.openfirmware.org/ofwg/practice/> | |
| 1232 | 1232 | |
| 1233 | 1233 | 1) interrupts property |
| 1234 | 1234 | ---------------------- |
| @@ -53,6 +53,14 @@ Struct Resources: · 52 unmodified lines | ||
| 53 | 53 | For printing struct resources. The 'R' and 'r' specifiers result in a |
| 54 | 54 | printed resource with ('R') or without ('r') a decoded flags member. |
| 55 | 55 | |
| 56 | +Physical addresses: | |
| 57 | + | |
| 58 | + %pa 0x01234567 or 0x0123456789abcdef | |
| 59 | + | |
| 60 | + For printing a phys_addr_t type (and its derivatives, such as | |
| 61 | + resource_size_t) which can vary based on build options, regardless of | |
| 62 | + the width of the CPU data path. Passed by reference. | |
| 63 | + | |
| 56 | 64 | Raw buffer as a hex string: |
| 57 | 65 | %*ph 00 01 02 ... 3f |
| 58 | 66 | %*phC 00:01:02: ... :3f |
| @@ -150,9 +158,9 @@ s64 SHOULD be printed with %lld/%llx, (long long): · 91 unmodified lines | ||
| 150 | 158 | printk("%lld", (long long)s64_var); |
| 151 | 159 | |
| 152 | 160 | If <type> is dependent on a config option for its size (e.g., sector_t, |
| 153 | −blkcnt_t, phys_addr_t, resource_size_t) or is architecture-dependent | |
| 154 | −for its size (e.g., tcflag_t), use a format specifier of its largest | |
| 155 | −possible type and explicitly cast to it. Example: | |
| 161 | +blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a | |
| 162 | +format specifier of its largest possible type and explicitly cast to it. | |
| 163 | +Example: | |
| 156 | 164 | |
| 157 | 165 | printk("test: sector number/total blocks: %llu/%llu\n", |
| 158 | 166 | (unsigned long long)sector, (unsigned long long)blockcount); |
| @@ -1956,7 +1956,8 @@ F: drivers/misc/* · 1955 unmodified lines | ||
| 1956 | 1956 | |
| 1957 | 1957 | CHECKPATCH |
| 1958 | 1958 | M: Andy Whitcroft <apw@canonical.com> |
| 1959 | −S: Supported | |
| 1959 | +M: Joe Perches <joe@perches.com> | |
| 1960 | +S: Maintained | |
| 1960 | 1961 | F: scripts/checkpatch.pl |
| 1961 | 1962 | |
| 1962 | 1963 | CHINESE DOCUMENTATION |
| @@ -5035,6 +5036,10 @@ L: linux-mm@kvack.org · 3072 unmodified lines | ||
| 5035 | 5036 | W: http://www.linux-mm.org |
| 5036 | 5037 | S: Maintained |
| 5037 | 5038 | F: include/linux/mm.h |
| 5039 | +F: include/linux/gfp.h | |
| 5040 | +F: include/linux/mmzone.h | |
| 5041 | +F: include/linux/memory_hotplug.h | |
| 5042 | +F: include/linux/vmalloc.h | |
| 5038 | 5043 | F: mm/ |
| 5039 | 5044 | |
| 5040 | 5045 | MEMORY RESOURCE CONTROLLER |
| @@ -1300,17 +1300,15 @@ static unsigned long · 1299 unmodified lines | ||
| 1300 | 1300 | arch_get_unmapped_area_1(unsigned long addr, unsigned long len, |
| 1301 | 1301 | unsigned long limit) |
| 1302 | 1302 | { |
| 1303 | − struct vm_area_struct *vma = find_vma(current->mm, addr); | |
| 1304 | − | |
| 1305 | − while (1) { | |
| 1306 | − /* At this point: (!vma || addr < vma->vm_end). */ | |
| 1307 | − if (limit - len < addr) | |
| 1308 | − return -ENOMEM; | |
| 1309 | − if (!vma || addr + len <= vma->vm_start) | |
| 1310 | − return addr; | |
| 1311 | − addr = vma->vm_end; | |
| 1312 | − vma = vma->vm_next; | |
| 1313 | − } | |
| 1303 | + struct vm_unmapped_area_info info; | |
| 1304 | + | |
| 1305 | + info.flags = 0; | |
| 1306 | + info.length = len; | |
| 1307 | + info.low_limit = addr; | |
| 1308 | + info.high_limit = limit; | |
| 1309 | + info.align_mask = 0; | |
| 1310 | + info.align_offset = 0; | |
| 1311 | + return vm_unmapped_area(&info); | |
| 1314 | 1312 | } |
| 1315 | 1313 | |
| 1316 | 1314 | unsigned long |
| @@ -131,6 +131,12 @@ · 130 unmodified lines | ||
| 131 | 131 | clocks = <&coreclk 0>; |
| 132 | 132 | status = "disabled"; |
| 133 | 133 | }; |
| 134 | + | |
| 135 | + rtc@10300 { | |
| 136 | + compatible = "marvell,orion-rtc"; | |
| 137 | + reg = <0xd0010300 0x20>; | |
| 138 | + interrupts = <50>; | |
| 139 | + }; | |
| 134 | 140 | }; |
| 135 | 141 | }; |
| 136 | 142 | |
| @@ -42,6 +42,14 @@ CONFIG_SMC91X=y · 41 unmodified lines | ||
| 42 | 42 | # CONFIG_SERIO is not set |
| 43 | 43 | CONFIG_SERIAL_PXA=y |
| 44 | 44 | CONFIG_SERIAL_PXA_CONSOLE=y |
| 45 | +CONFIG_SPI=y | |
| 46 | +CONFIG_FB=y | |
| 47 | +CONFIG_MMP_DISP=y | |
| 48 | +CONFIG_MMP_DISP_CONTROLLER=y | |
| 49 | +CONFIG_MMP_SPI=y | |
| 50 | +CONFIG_MMP_PANEL_TPOHVGA=y | |
| 51 | +CONFIG_MMP_FB=y | |
| 52 | +CONFIG_LOGO=y | |
| 45 | 53 | # CONFIG_LEGACY_PTYS is not set |
| 46 | 54 | # CONFIG_HW_RANDOM is not set |
| 47 | 55 | # CONFIG_HWMON is not set |
| @@ -8,6 +8,7 @@ extern void __init pxa910_init_irq(void); · 7 unmodified lines | ||
| 8 | 8 | #include <linux/i2c/pxa-i2c.h> |
| 9 | 9 | #include <mach/devices.h> |
| 10 | 10 | #include <linux/platform_data/mtd-nand-pxa3xx.h> |
| 11 | +#include <video/mmp_disp.h> | |
| 11 | 12 | |
| 12 | 13 | extern struct pxa_device_desc pxa910_device_uart1; |
| 13 | 14 | extern struct pxa_device_desc pxa910_device_uart2; |
| @@ -21,7 +22,9 @@ extern struct pxa_device_desc pxa910_device_nand; · 7 unmodified lines | ||
| 21 | 22 | extern struct platform_device pxa168_device_u2o; |
| 22 | 23 | extern struct platform_device pxa168_device_u2ootg; |
| 23 | 24 | extern struct platform_device pxa168_device_u2oehci; |
| 24 | − | |
| 25 | +extern struct pxa_device_desc pxa910_device_disp; | |
| 26 | +extern struct pxa_device_desc pxa910_device_fb; | |
| 27 | +extern struct pxa_device_desc pxa910_device_panel; | |
| 25 | 28 | extern struct platform_device pxa910_device_gpio; |
| 26 | 29 | extern struct platform_device pxa910_device_rtc; |
| 27 | 30 | |
| @@ -134,6 +134,9 @@ PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10); · 133 unmodified lines | ||
| 134 | 134 | PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10); |
| 135 | 135 | PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10); |
| 136 | 136 | PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99); |
| 137 | +PXA910_DEVICE(disp, "mmp-disp", 0, LCD, 0xd420b000, 0x1ec); | |
| 138 | +PXA910_DEVICE(fb, "mmp-fb", -1, NONE, 0, 0); | |
| 139 | +PXA910_DEVICE(panel, "tpo-hvga", -1, NONE, 0, 0); | |
| 137 | 140 | |
| 138 | 141 | struct resource pxa910_resource_gpio[] = { |
| 139 | 142 | { |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/gpio.h> |
| 20 | 20 | #include <linux/mfd/88pm860x.h> |
| 21 | 21 | #include <linux/platform_data/mv_usb.h> |
| 22 | +#include <linux/spi/spi.h> | |
| 23 | +#include <linux/delay.h> | |
| 22 | 24 | |
| 23 | 25 | #include <asm/mach-types.h> |
| 24 | 26 | #include <asm/mach/arch.h> |
| @@ -184,6 +186,92 @@ static struct pxa3xx_nand_platform_data dkb_nand_info = { · 159 unmodified lines | ||
| 184 | 186 | }; |
| 185 | 187 | #endif |
| 186 | 188 | |
| 189 | +#ifdef CONFIG_MMP_DISP | |
| 190 | +/* path config */ | |
| 191 | +#define CFG_IOPADMODE(iopad) (iopad) /* 0x0 ~ 0xd */ | |
| 192 | +#define SCLK_SOURCE_SELECT(x) (x << 30) /* 0x0 ~ 0x3 */ | |
| 193 | +/* link config */ | |
| 194 | +#define CFG_DUMBMODE(mode) (mode << 28) /* 0x0 ~ 0x6*/ | |
| 195 | +#define CFG_GRA_SWAPRB(x) (x << 0) /* 1: rbswap enabled */ | |
| 196 | +static struct mmp_mach_path_config dkb_disp_config[] = { | |
| 197 | + [0] = { | |
| 198 | + .name = "mmp-parallel", | |
| 199 | + .overlay_num = 2, | |
| 200 | + .output_type = PATH_OUT_PARALLEL, | |
| 201 | + .path_config = CFG_IOPADMODE(0x1) | |
| 202 | + | SCLK_SOURCE_SELECT(0x1), | |
| 203 | + .link_config = CFG_DUMBMODE(0x2) | |
| 204 | + | CFG_GRA_SWAPRB(0x1), | |
| 205 | + }, | |
| 206 | +}; | |
| 207 | + | |
| 208 | +static struct mmp_mach_plat_info dkb_disp_info = { | |
| 209 | + .name = "mmp-disp", | |
| 210 | + .clk_name = "disp0", | |
| 211 | + .path_num = 1, | |
| 212 | + .paths = dkb_disp_config, | |
| 213 | +}; | |
| 214 | + | |
| 215 | +static struct mmp_buffer_driver_mach_info dkb_fb_info = { | |
| 216 | + .name = "mmp-fb", | |
| 217 | + .path_name = "mmp-parallel", | |
| 218 | + .overlay_id = 0, | |
| 219 | + .dmafetch_id = 1, | |
| 220 | + .default_pixfmt = PIXFMT_RGB565, | |
| 221 | +}; | |
| 222 | + | |
| 223 | +static void dkb_tpo_panel_power(int on) | |
| 224 | +{ | |
| 225 | + int err; | |
| 226 | + u32 spi_reset = mfp_to_gpio(MFP_PIN_GPIO106); | |
| 227 | + | |
| 228 | + if (on) { | |
| 229 | + err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET"); | |
| 230 | + if (err) { | |
| 231 | + pr_err("failed to request GPIO for TPO LCD RESET\n"); | |
| 232 | + return; | |
| 233 | + } | |
| 234 | + gpio_direction_output(spi_reset, 0); | |
| 235 | + udelay(100); | |
| 236 | + gpio_set_value(spi_reset, 1); | |
| 237 | + gpio_free(spi_reset); | |
| 238 | + } else { | |
| 239 | + err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET"); | |
| 240 | + if (err) { | |
| 241 | + pr_err("failed to request LCD RESET gpio\n"); | |
| 242 | + return; | |
| 243 | + } | |
| 244 | + gpio_set_value(spi_reset, 0); | |
| 245 | + gpio_free(spi_reset); | |
| 246 | + } | |
| 247 | +} | |
| 248 | + | |
| 249 | +static struct mmp_mach_panel_info dkb_tpo_panel_info = { | |
| 250 | + .name = "tpo-hvga", | |
| 251 | + .plat_path_name = "mmp-parallel", | |
| 252 | + .plat_set_onoff = dkb_tpo_panel_power, | |
| 253 | +}; | |
| 254 | + | |
| 255 | +static struct spi_board_info spi_board_info[] __initdata = { | |
| 256 | + { | |
| 257 | + .modalias = "tpo-hvga", | |
| 258 | + .platform_data = &dkb_tpo_panel_info, | |
| 259 | + .bus_num = 5, | |
| 260 | + } | |
| 261 | +}; | |
| 262 | + | |
| 263 | +static void __init add_disp(void) | |
| 264 | +{ | |
| 265 | + pxa_register_device(&pxa910_device_disp, | |
| 266 | + &dkb_disp_info, sizeof(dkb_disp_info)); | |
| 267 | + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); | |
| 268 | + pxa_register_device(&pxa910_device_fb, | |
| 269 | + &dkb_fb_info, sizeof(dkb_fb_info)); | |
| 270 | + pxa_register_device(&pxa910_device_panel, | |
| 271 | + &dkb_tpo_panel_info, sizeof(dkb_tpo_panel_info)); | |
| 272 | +} | |
| 273 | +#endif | |
| 274 | + | |
| 187 | 275 | static void __init ttc_dkb_init(void) |
| 188 | 276 | { |
| 189 | 277 | mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config)); |
| @@ -212,6 +300,10 @@ static void __init ttc_dkb_init(void) · 22 unmodified lines | ||
| 212 | 300 | pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata; |
| 213 | 301 | platform_device_register(&pxa168_device_u2ootg); |
| 214 | 302 | #endif |
| 303 | + | |
| 304 | +#ifdef CONFIG_MMP_DISP | |
| 305 | + add_disp(); | |
| 306 | +#endif | |
| 215 | 307 | } |
| 216 | 308 | |
| 217 | 309 | MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform") |
| @@ -22,11 +22,6 @@ typedef unsigned short __kernel_uid_t; · 21 unmodified lines | ||
| 22 | 22 | typedef unsigned short __kernel_gid_t; |
| 23 | 23 | #define __kernel_uid_t __kernel_uid_t |
| 24 | 24 | |
| 25 | −typedef __SIZE_TYPE__ __kernel_size_t; | |
| 26 | −typedef long __kernel_ssize_t; | |
| 27 | −typedef int __kernel_ptrdiff_t; | |
| 28 | −#define __kernel_size_t __kernel_size_t | |
| 29 | − | |
| 30 | 25 | typedef unsigned short __kernel_old_dev_t; |
| 31 | 26 | #define __kernel_old_dev_t __kernel_old_dev_t |
| 32 | 27 | |
| @@ -29,7 +29,7 @@ void __init pcibios_fixup_irqs(void) · 28 unmodified lines | ||
| 29 | 29 | struct pci_dev *dev = NULL; |
| 30 | 30 | u8 line, pin; |
| 31 | 31 | |
| 32 | − while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | |
| 32 | + for_each_pci_dev(dev) { | |
| 33 | 33 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); |
| 34 | 34 | if (pin) { |
| 35 | 35 | dev->irq = XIRQ1; |
| @@ -413,12 +413,6 @@ config TILE_USB · 412 unmodified lines | ||
| 413 | 413 | Provides USB host adapter support for the built-in EHCI and OHCI |
| 414 | 414 | interfaces on TILE-Gx chips. |
| 415 | 415 | |
| 416 | −# USB OHCI needs the bounce pool since tilegx will often have more | |
| 417 | −# than 4GB of memory, but we don't currently use the IOTLB to present | |
| 418 | −# a 32-bit address to OHCI. So we need to use a bounce pool instead. | |
| 419 | −config NEED_BOUNCE_POOL | |
| 420 | − def_bool USB_OHCI_HCD | |
| 421 | − | |
| 422 | 416 | source "drivers/pci/hotplug/Kconfig" |
| 423 | 417 | |
| 424 | 418 | endmenu |
| @@ -1474,6 +1474,11 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio) · 1473 unmodified lines | ||
| 1474 | 1474 | */ |
| 1475 | 1475 | blk_queue_bounce(q, &bio); |
| 1476 | 1476 | |
| 1477 | + if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { | |
| 1478 | + bio_endio(bio, -EIO); | |
| 1479 | + return; | |
| 1480 | + } | |
| 1481 | + | |
| 1477 | 1482 | if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) { |
| 1478 | 1483 | spin_lock_irq(q->queue_lock); |
| 1479 | 1484 | where = ELEVATOR_INSERT_FLUSH; |
| @@ -1714,9 +1719,6 @@ generic_make_request_checks(struct bio *bio) · 234 unmodified lines | ||
| 1714 | 1719 | */ |
| 1715 | 1720 | blk_partition_remap(bio); |
| 1716 | 1721 | |
| 1717 | − if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) | |
| 1718 | − goto end_io; | |
| 1719 | − | |
| 1720 | 1722 | if (bio_check_eod(bio, nr_sectors)) |
| 1721 | 1723 | goto end_io; |
| 1722 | 1724 | |
| @@ -420,6 +420,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) · 419 unmodified lines | ||
| 420 | 420 | } else |
| 421 | 421 | bi->name = bi_unsupported_name; |
| 422 | 422 | |
| 423 | + disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES; | |
| 424 | + | |
| 423 | 425 | return 0; |
| 424 | 426 | } |
| 425 | 427 | EXPORT_SYMBOL(blk_integrity_register); |
| @@ -438,6 +440,8 @@ void blk_integrity_unregister(struct gendisk *disk) · 12 unmodified lines | ||
| 438 | 440 | if (!disk || !disk->integrity) |
| 439 | 441 | return; |
| 440 | 442 | |
| 443 | + disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES; | |
| 444 | + | |
| 441 | 445 | bi = disk->integrity; |
| 442 | 446 | |
| 443 | 447 | kobject_uevent(&bi->kobj, KOBJ_REMOVE); |
| @@ -61,7 +61,7 @@ config SUNGEM · 60 unmodified lines | ||
| 61 | 61 | select SUNGEM_PHY |
| 62 | 62 | ---help--- |
| 63 | 63 | Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also |
| 64 | − <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>. | |
| 64 | + <http://docs.oracle.com/cd/E19455-01/806-3985-10/806-3985-10.pdf>. | |
| 65 | 65 | |
| 66 | 66 | config CASSINI |
| 67 | 67 | tristate "Sun Cassini support" |
| @@ -69,7 +69,7 @@ config CASSINI · 1 unmodified line | ||
| 69 | 69 | select CRC32 |
| 70 | 70 | ---help--- |
| 71 | 71 | Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also |
| 72 | − <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf> | |
| 72 | + <http://docs.oracle.com/cd/E19113-01/giga.ether.pci/817-4341-10/817-4341-10.pdf>. | |
| 73 | 73 | |
| 74 | 74 | config SUNVNET |
| 75 | 75 | tristate "Sun Virtual Network support" |
| @@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt) · 483 unmodified lines | ||
| 484 | 484 | |
| 485 | 485 | static int socket_late_resume(struct pcmcia_socket *skt) |
| 486 | 486 | { |
| 487 | − int ret; | |
| 487 | + int ret = 0; | |
| 488 | 488 | |
| 489 | 489 | mutex_lock(&skt->ops_mutex); |
| 490 | 490 | skt->state &= ~SOCKET_SUSPEND; |
| @@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt) · 20 unmodified lines | ||
| 511 | 511 | return socket_insert(skt); |
| 512 | 512 | } |
| 513 | 513 | |
| 514 | + if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) | |
| 515 | + ret = skt->callback->early_resume(skt); | |
| 516 | + return ret; | |
| 517 | +} | |
| 518 | + | |
| 519 | +/* | |
| 520 | + * Finalize the resume. In case of a cardbus socket, we have | |
| 521 | + * to rebind the devices as we can't be certain that it has been | |
| 522 | + * replaced, or not. | |
| 523 | + */ | |
| 524 | +static int socket_complete_resume(struct pcmcia_socket *skt) | |
| 525 | +{ | |
| 526 | + int ret = 0; | |
| 514 | 527 | #ifdef CONFIG_CARDBUS |
| 515 | 528 | if (skt->state & SOCKET_CARDBUS) { |
| 516 | 529 | /* We can't be sure the CardBus card is the same |
| 517 | 530 | * as the one previously inserted. Therefore, remove |
| 518 | 531 | * and re-add... */ |
| 519 | 532 | cb_free(skt); |
| 520 | − cb_alloc(skt); | |
| 521 | − return 0; | |
| 533 | + ret = cb_alloc(skt); | |
| 534 | + if (ret) | |
| 535 | + cb_free(skt); | |
| 522 | 536 | } |
| 523 | 537 | #endif |
| 524 | − if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) | |
| 525 | − skt->callback->early_resume(skt); | |
| 526 | − return 0; | |
| 538 | + return ret; | |
| 527 | 539 | } |
| 528 | 540 | |
| 529 | 541 | /* |
| @@ -533,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt) · 3 unmodified lines | ||
| 533 | 545 | */ |
| 534 | 546 | static int socket_resume(struct pcmcia_socket *skt) |
| 535 | 547 | { |
| 548 | + int err; | |
| 536 | 549 | if (!(skt->state & SOCKET_SUSPEND)) |
| 537 | 550 | return -EBUSY; |
| 538 | 551 | |
| 539 | 552 | socket_early_resume(skt); |
| 540 | − return socket_late_resume(skt); | |
| 553 | + err = socket_late_resume(skt); | |
| 554 | + if (!err) | |
| 555 | + err = socket_complete_resume(skt); | |
| 556 | + return err; | |
| 541 | 557 | } |
| 542 | 558 | |
| 543 | 559 | static void socket_remove(struct pcmcia_socket *skt) |
| @@ -848,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev) · 304 unmodified lines | ||
| 848 | 864 | return __pcmcia_pm_op(dev, socket_late_resume); |
| 849 | 865 | } |
| 850 | 866 | |
| 867 | +static void __used pcmcia_socket_dev_complete(struct device *dev) | |
| 868 | +{ | |
| 869 | + WARN(__pcmcia_pm_op(dev, socket_complete_resume), | |
| 870 | + "failed to complete resume"); | |
| 871 | +} | |
| 872 | + | |
| 851 | 873 | static const struct dev_pm_ops pcmcia_socket_pm_ops = { |
| 852 | 874 | /* dev_resume may be called with IRQs enabled */ |
| 853 | 875 | SET_SYSTEM_SLEEP_PM_OPS(NULL, |
| @@ -862,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = { · 8 unmodified lines | ||
| 862 | 884 | .resume_noirq = pcmcia_socket_dev_resume_noirq, |
| 863 | 885 | .thaw_noirq = pcmcia_socket_dev_resume_noirq, |
| 864 | 886 | .restore_noirq = pcmcia_socket_dev_resume_noirq, |
| 887 | + .complete = pcmcia_socket_dev_complete, | |
| 865 | 888 | }; |
| 866 | 889 | |
| 867 | 890 | #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) |
| @@ -204,6 +204,12 @@ config RTC_DRV_DS3232 · 203 unmodified lines | ||
| 204 | 204 | This driver can also be built as a module. If so, the module |
| 205 | 205 | will be called rtc-ds3232. |
| 206 | 206 | |
| 207 | +config RTC_DRV_LP8788 | |
| 208 | + tristate "TI LP8788 RTC driver" | |
| 209 | + depends on MFD_LP8788 | |
| 210 | + help | |
| 211 | + Say Y to enable support for the LP8788 RTC/ALARM driver. | |
| 212 | + | |
| 207 | 213 | config RTC_DRV_MAX6900 |
| 208 | 214 | tristate "Maxim MAX6900" |
| 209 | 215 | help |
| @@ -243,6 +249,26 @@ config RTC_DRV_MAX8998 · 33 unmodified lines | ||
| 243 | 249 | This driver can also be built as a module. If so, the module |
| 244 | 250 | will be called rtc-max8998. |
| 245 | 251 | |
| 252 | +config RTC_DRV_MAX8997 | |
| 253 | + tristate "Maxim MAX8997" | |
| 254 | + depends on MFD_MAX8997 | |
| 255 | + help | |
| 256 | + If you say yes here you will get support for the | |
| 257 | + RTC of Maxim MAX8997 PMIC. | |
| 258 | + | |
| 259 | + This driver can also be built as a module. If so, the module | |
| 260 | + will be called rtc-max8997. | |
| 261 | + | |
| 262 | +config RTC_DRV_MAX77686 | |
| 263 | + tristate "Maxim MAX77686" | |
| 264 | + depends on MFD_MAX77686 | |
| 265 | + help | |
| 266 | + If you say yes here you will get support for the | |
| 267 | + RTC of Maxim MAX77686 PMIC. | |
| 268 | + | |
| 269 | + This driver can also be built as a module. If so, the module | |
| 270 | + will be called rtc-max77686. | |
| 271 | + | |
| 246 | 272 | config RTC_DRV_RS5C372 |
| 247 | 273 | tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" |
| 248 | 274 | help |
| @@ -380,6 +406,14 @@ config RTC_DRV_TPS65910 · 131 unmodified lines | ||
| 380 | 406 | This driver can also be built as a module. If so, the module |
| 381 | 407 | will be called rtc-tps65910. |
| 382 | 408 | |
| 409 | +config RTC_DRV_TPS80031 | |
| 410 | + tristate "TI TPS80031/TPS80032 RTC driver" | |
| 411 | + depends on MFD_TPS80031 | |
| 412 | + help | |
| 413 | + TI Power Managment IC TPS80031 supports RTC functionality | |
| 414 | + along with alarm. This driver supports the RTC driver for | |
| 415 | + the TPS80031 RTC module. | |
| 416 | + | |
| 383 | 417 | config RTC_DRV_RC5T583 |
| 384 | 418 | tristate "RICOH 5T583 RTC driver" |
| 385 | 419 | depends on MFD_RC5T583 |
| @@ -537,6 +571,14 @@ config RTC_DRV_PCF2123 · 151 unmodified lines | ||
| 537 | 571 | This driver can also be built as a module. If so, the module |
| 538 | 572 | will be called rtc-pcf2123. |
| 539 | 573 | |
| 574 | +config RTC_DRV_RX4581 | |
| 575 | + tristate "Epson RX-4581" | |
| 576 | + help | |
| 577 | + If you say yes here you will get support for the Epson RX-4581. | |
| 578 | + | |
| 579 | + This driver can also be built as a module. If so the module | |
| 580 | + will be called rtc-rx4581. | |
| 581 | + | |
| 540 | 582 | endif # SPI_MASTER |
| 541 | 583 | |
| 542 | 584 | comment "Platform RTC drivers" |
| @@ -58,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o · 57 unmodified lines | ||
| 58 | 58 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o |
| 59 | 59 | obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o |
| 60 | 60 | obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o |
| 61 | +obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o | |
| 61 | 62 | obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o |
| 62 | 63 | obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o |
| 63 | 64 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o |
| @@ -71,7 +72,9 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o · 7 unmodified lines | ||
| 71 | 72 | obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o |
| 72 | 73 | obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o |
| 73 | 74 | obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o |
| 75 | +obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o | |
| 74 | 76 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o |
| 77 | +obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o | |
| 75 | 78 | obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o |
| 76 | 79 | obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o |
| 77 | 80 | obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o |
| @@ -97,6 +100,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o · 19 unmodified lines | ||
| 97 | 100 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o |
| 98 | 101 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
| 99 | 102 | obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o |
| 103 | +obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o | |
| 100 | 104 | obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o |
| 101 | 105 | obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o |
| 102 | 106 | obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o |
| @@ -115,6 +119,7 @@ obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o · 12 unmodified lines | ||
| 115 | 119 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o |
| 116 | 120 | obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o |
| 117 | 121 | obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o |
| 122 | +obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o | |
| 118 | 123 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o |
| 119 | 124 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o |
| 120 | 125 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | * published by the Free Software Foundation. |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 15 | + | |
| 14 | 16 | #include <linux/module.h> |
| 15 | 17 | #include <linux/rtc.h> |
| 16 | 18 | #include <linux/kdev_t.h> |
| @@ -261,7 +263,7 @@ static int __init rtc_init(void) · 244 unmodified lines | ||
| 261 | 263 | { |
| 262 | 264 | rtc_class = class_create(THIS_MODULE, "rtc"); |
| 263 | 265 | if (IS_ERR(rtc_class)) { |
| 264 | − printk(KERN_ERR "%s: couldn't create class\n", __FILE__); | |
| 266 | + pr_err("couldn't create class\n"); | |
| 265 | 267 | return PTR_ERR(rtc_class); |
| 266 | 268 | } |
| 267 | 269 | rtc_class->suspend = rtc_suspend; |
| @@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) · 85 unmodified lines | ||
| 86 | 86 | tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); |
| 87 | 87 | tm->tm_year = tm->tm_year - 1900; |
| 88 | 88 | |
| 89 | − pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 89 | + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 90 | 90 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
| 91 | 91 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
| 92 | 92 | |
| @@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) · 7 unmodified lines | ||
| 100 | 100 | { |
| 101 | 101 | unsigned long cr; |
| 102 | 102 | |
| 103 | − pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 103 | + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 104 | 104 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
| 105 | 105 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
| 106 | 106 | |
| @@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) · 38 unmodified lines | ||
| 145 | 145 | alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM) |
| 146 | 146 | ? 1 : 0; |
| 147 | 147 | |
| 148 | − pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 148 | + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 149 | 149 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
| 150 | 150 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
| 151 | 151 | |
| @@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) · 31 unmodified lines | ||
| 183 | 183 | at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | − pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 186 | + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 187 | 187 | at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, |
| 188 | 188 | tm.tm_min, tm.tm_sec); |
| 189 | 189 | |
| @@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) · 2 unmodified lines | ||
| 192 | 192 | |
| 193 | 193 | static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
| 194 | 194 | { |
| 195 | − pr_debug("%s(): cmd=%08x\n", __func__, enabled); | |
| 195 | + dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled); | |
| 196 | 196 | |
| 197 | 197 | if (enabled) { |
| 198 | 198 | at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); |
| @@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) · 41 unmodified lines | ||
| 240 | 240 | |
| 241 | 241 | rtc_update_irq(rtc, 1, events); |
| 242 | 242 | |
| 243 | − pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__, | |
| 243 | + dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__, | |
| 244 | 244 | events >> 8, events & 0x000000FF); |
| 245 | 245 | |
| 246 | 246 | return IRQ_HANDLED; |
| @@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) · 49 unmodified lines | ||
| 296 | 296 | IRQF_SHARED, |
| 297 | 297 | "at91_rtc", pdev); |
| 298 | 298 | if (ret) { |
| 299 | − printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", | |
| 300 | − irq); | |
| 299 | + dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); | |
| 301 | 300 | return ret; |
| 302 | 301 | } |
| 303 | 302 | |
| @@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) · 11 unmodified lines | ||
| 315 | 314 | } |
| 316 | 315 | platform_set_drvdata(pdev, rtc); |
| 317 | 316 | |
| 318 | − printk(KERN_INFO "AT91 Real Time Clock driver.\n"); | |
| 317 | + dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); | |
| 319 | 318 | return 0; |
| 320 | 319 | } |
| 321 | 320 | |
| @@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) · 705 unmodified lines | ||
| 706 | 706 | rtc_cmos_int_handler = hpet_rtc_interrupt; |
| 707 | 707 | err = hpet_register_irq_handler(cmos_interrupt); |
| 708 | 708 | if (err != 0) { |
| 709 | − printk(KERN_WARNING "hpet_register_irq_handler " | |
| 709 | + dev_warn(dev, "hpet_register_irq_handler " | |
| 710 | 710 | " failed in rtc_init()."); |
| 711 | 711 | goto cleanup1; |
| 712 | 712 | } |
| @@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) · 18 unmodified lines | ||
| 731 | 731 | goto cleanup2; |
| 732 | 732 | } |
| 733 | 733 | |
| 734 | − pr_info("%s: %s%s, %zd bytes nvram%s\n", | |
| 735 | − dev_name(&cmos_rtc.rtc->dev), | |
| 734 | + dev_info(dev, "%s%s, %zd bytes nvram%s\n", | |
| 736 | 735 | !is_valid_irq(rtc_irq) ? "no alarms" : |
| 737 | 736 | cmos_rtc.mon_alrm ? "alarms up to one year" : |
| 738 | 737 | cmos_rtc.day_alrm ? "alarms up to one month" : |
| @@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev) · 81 unmodified lines | ||
| 820 | 819 | enable_irq_wake(cmos->irq); |
| 821 | 820 | } |
| 822 | 821 | |
| 823 | − pr_debug("%s: suspend%s, ctrl %02x\n", | |
| 824 | − dev_name(&cmos_rtc.rtc->dev), | |
| 822 | + dev_dbg(dev, "suspend%s, ctrl %02x\n", | |
| 825 | 823 | (tmp & RTC_AIE) ? ", alarm may wake" : "", |
| 826 | 824 | tmp); |
| 827 | 825 | |
| @@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev) · 48 unmodified lines | ||
| 876 | 874 | spin_unlock_irq(&rtc_lock); |
| 877 | 875 | } |
| 878 | 876 | |
| 879 | − pr_debug("%s: resume, ctrl %02x\n", | |
| 880 | − dev_name(&cmos_rtc.rtc->dev), | |
| 881 | − tmp); | |
| 877 | + dev_dbg(dev, "resume, ctrl %02x\n", tmp); | |
| 882 | 878 | |
| 883 | 879 | return 0; |
| 884 | 880 | } |
| @@ -1098,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev) · 213 unmodified lines | ||
| 1098 | 1094 | } |
| 1099 | 1095 | #else |
| 1100 | 1096 | static inline void cmos_of_init(struct platform_device *pdev) {} |
| 1101 | −#define of_cmos_match NULL | |
| 1102 | 1097 | #endif |
| 1103 | 1098 | /*----------------------------------------------------------------*/ |
| 1104 | 1099 | |
| @@ -1140,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = { · 35 unmodified lines | ||
| 1140 | 1135 | #ifdef CONFIG_PM |
| 1141 | 1136 | .pm = &cmos_pm_ops, |
| 1142 | 1137 | #endif |
| 1143 | − .of_match_table = of_cmos_match, | |
| 1138 | + .of_match_table = of_match_ptr(of_cmos_match), | |
| 1144 | 1139 | } |
| 1145 | 1140 | }; |
| 1146 | 1141 | |
| @@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev) · 156 unmodified lines | ||
| 157 | 157 | if (rtap) { |
| 158 | 158 | rtc_device_unregister(rtap->rtc); |
| 159 | 159 | clk_unprepare(rtap->clk); |
| 160 | − clk_put(rtap->clk); | |
| 161 | 160 | platform_set_drvdata(pdev, NULL); |
| 162 | 161 | } |
| 163 | 162 | |
| @@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev) · 32 unmodified lines | ||
| 196 | 195 | "RTC COH 901 331 Alarm", rtap)) |
| 197 | 196 | return -EIO; |
| 198 | 197 | |
| 199 | − rtap->clk = clk_get(&pdev->dev, NULL); | |
| 198 | + rtap->clk = devm_clk_get(&pdev->dev, NULL); | |
| 200 | 199 | if (IS_ERR(rtap->clk)) { |
| 201 | 200 | ret = PTR_ERR(rtap->clk); |
| 202 | 201 | dev_err(&pdev->dev, "could not get clock\n"); |
| @@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 207 | 206 | ret = clk_prepare_enable(rtap->clk); |
| 208 | 207 | if (ret) { |
| 209 | 208 | dev_err(&pdev->dev, "could not enable clock\n"); |
| 210 | − goto out_no_clk_prepenable; | |
| 209 | + return ret; | |
| 211 | 210 | } |
| 212 | 211 | clk_disable(rtap->clk); |
| 213 | 212 | |
| @@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev) · 10 unmodified lines | ||
| 224 | 223 | out_no_rtc: |
| 225 | 224 | platform_set_drvdata(pdev, NULL); |
| 226 | 225 | clk_unprepare(rtap->clk); |
| 227 | − out_no_clk_prepenable: | |
| 228 | − clk_put(rtap->clk); | |
| 229 | 226 | return ret; |
| 230 | 227 | } |
| 231 | 228 | |
| @@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev) · 239 unmodified lines | ||
| 240 | 240 | rtc->da9052 = dev_get_drvdata(pdev->dev.parent); |
| 241 | 241 | platform_set_drvdata(pdev, rtc); |
| 242 | 242 | rtc->irq = platform_get_irq_byname(pdev, "ALM"); |
| 243 | − ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq, | |
| 244 | − IRQF_TRIGGER_LOW | IRQF_ONESHOT, | |
| 245 | − "ALM", rtc); | |
| 243 | + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | |
| 244 | + da9052_rtc_irq, | |
| 245 | + IRQF_TRIGGER_LOW | IRQF_ONESHOT, | |
| 246 | + "ALM", rtc); | |
| 246 | 247 | if (ret != 0) { |
| 247 | 248 | rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); |
| 248 | 249 | return ret; |
| @@ -250,16 +251,10 @@ static int da9052_rtc_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 250 | 251 | |
| 251 | 252 | rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, |
| 252 | 253 | &da9052_rtc_ops, THIS_MODULE); |
| 253 | − if (IS_ERR(rtc->rtc)) { | |
| 254 | − ret = PTR_ERR(rtc->rtc); | |
| 255 | − goto err_free_irq; | |
| 256 | − } | |
| 254 | + if (IS_ERR(rtc->rtc)) | |
| 255 | + return PTR_ERR(rtc->rtc); | |
| 257 | 256 | |
| 258 | 257 | return 0; |
| 259 | − | |
| 260 | −err_free_irq: | |
| 261 | − free_irq(rtc->irq, rtc); | |
| 262 | − return ret; | |
| 263 | 258 | } |
| 264 | 259 | |
| 265 | 260 | static int da9052_rtc_remove(struct platform_device *pdev) |
| @@ -267,7 +262,6 @@ static int da9052_rtc_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 267 | 262 | struct da9052_rtc *rtc = pdev->dev.platform_data; |
| 268 | 263 | |
| 269 | 264 | rtc_device_unregister(rtc->rtc); |
| 270 | − free_irq(rtc->irq, rtc); | |
| 271 | 265 | platform_set_drvdata(pdev, NULL); |
| 272 | 266 | |
| 273 | 267 | return 0; |
| @@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) · 505 unmodified lines | ||
| 506 | 506 | davinci_rtc->pbase = res->start; |
| 507 | 507 | davinci_rtc->base_size = resource_size(res); |
| 508 | 508 | |
| 509 | − mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size, | |
| 510 | − pdev->name); | |
| 509 | + mem = devm_request_mem_region(dev, davinci_rtc->pbase, | |
| 510 | + davinci_rtc->base_size, pdev->name); | |
| 511 | 511 | if (!mem) { |
| 512 | 512 | dev_err(dev, "RTC registers at %08x are not free\n", |
| 513 | 513 | davinci_rtc->pbase); |
| 514 | 514 | return -EBUSY; |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | − davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); | |
| 517 | + davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase, | |
| 518 | + davinci_rtc->base_size); | |
| 518 | 519 | if (!davinci_rtc->base) { |
| 519 | 520 | dev_err(dev, "unable to ioremap MEM resource\n"); |
| 520 | − ret = -ENOMEM; | |
| 521 | − goto fail2; | |
| 521 | + return -ENOMEM; | |
| 522 | 522 | } |
| 523 | 523 | |
| 524 | 524 | platform_set_drvdata(pdev, davinci_rtc); |
| @@ -529,7 +529,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 529 | 529 | ret = PTR_ERR(davinci_rtc->rtc); |
| 530 | 530 | dev_err(dev, "unable to register RTC device, err %d\n", |
| 531 | 531 | ret); |
| 532 | − goto fail3; | |
| 532 | + goto fail1; | |
| 533 | 533 | } |
| 534 | 534 | |
| 535 | 535 | rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); |
| @@ -539,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 539 | 539 | rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); |
| 540 | 540 | rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); |
| 541 | 541 | |
| 542 | − ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt, | |
| 542 | + ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt, | |
| 543 | 543 | 0, "davinci_rtc", davinci_rtc); |
| 544 | 544 | if (ret < 0) { |
| 545 | 545 | dev_err(dev, "unable to register davinci RTC interrupt\n"); |
| 546 | − goto fail4; | |
| 546 | + goto fail2; | |
| 547 | 547 | } |
| 548 | 548 | |
| 549 | 549 | /* Enable interrupts */ |
| @@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) · 7 unmodified lines | ||
| 557 | 557 | |
| 558 | 558 | return 0; |
| 559 | 559 | |
| 560 | −fail4: | |
| 560 | +fail2: | |
| 561 | 561 | rtc_device_unregister(davinci_rtc->rtc); |
| 562 | −fail3: | |
| 562 | +fail1: | |
| 563 | 563 | platform_set_drvdata(pdev, NULL); |
| 564 | − iounmap(davinci_rtc->base); | |
| 565 | −fail2: | |
| 566 | − release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); | |
| 567 | 564 | return ret; |
| 568 | 565 | } |
| 569 | 566 | |
| @@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev) · 5 unmodified lines | ||
| 575 | 572 | |
| 576 | 573 | rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); |
| 577 | 574 | |
| 578 | − free_irq(davinci_rtc->irq, davinci_rtc); | |
| 579 | − | |
| 580 | 575 | rtc_device_unregister(davinci_rtc->rtc); |
| 581 | 576 | |
| 582 | − iounmap(davinci_rtc->base); | |
| 583 | − release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); | |
| 584 | − | |
| 585 | 577 | platform_set_drvdata(pdev, NULL); |
| 586 | 578 | |
| 587 | 579 | return 0; |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | * published by the Free Software Foundation. |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 15 | + | |
| 14 | 16 | #include <linux/module.h> |
| 15 | 17 | #include <linux/rtc.h> |
| 16 | 18 | #include <linux/sched.h> |
| @@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) · 445 unmodified lines | ||
| 462 | 464 | return; |
| 463 | 465 | |
| 464 | 466 | if (rtc->id >= RTC_DEV_MAX) { |
| 465 | − pr_debug("%s: too many RTC devices\n", rtc->name); | |
| 467 | + dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name); | |
| 466 | 468 | return; |
| 467 | 469 | } |
| 468 | 470 | |
| @@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc) · 11 unmodified lines | ||
| 480 | 482 | void rtc_dev_add_device(struct rtc_device *rtc) |
| 481 | 483 | { |
| 482 | 484 | if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) |
| 483 | − printk(KERN_WARNING "%s: failed to add char device %d:%d\n", | |
| 485 | + dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", | |
| 484 | 486 | rtc->name, MAJOR(rtc_devt), rtc->id); |
| 485 | 487 | else |
| 486 | − pr_debug("%s: dev (%d:%d)\n", rtc->name, | |
| 488 | + dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, | |
| 487 | 489 | MAJOR(rtc_devt), rtc->id); |
| 488 | 490 | } |
| 489 | 491 | |
| @@ -499,8 +501,7 @@ void __init rtc_dev_init(void) · 9 unmodified lines | ||
| 499 | 501 | |
| 500 | 502 | err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); |
| 501 | 503 | if (err < 0) |
| 502 | − printk(KERN_ERR "%s: failed to allocate char dev region\n", | |
| 503 | − __FILE__); | |
| 504 | + pr_err("failed to allocate char dev region\n"); | |
| 504 | 505 | } |
| 505 | 506 | |
| 506 | 507 | void __exit rtc_dev_exit(void) |
| @@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi) · 634 unmodified lines | ||
| 635 | 635 | goto fail0; |
| 636 | 636 | } |
| 637 | 637 | |
| 638 | − dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", | |
| 639 | − "read", ds1305->ctrl[0], | |
| 640 | − ds1305->ctrl[1], ds1305->ctrl[2]); | |
| 638 | + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl); | |
| 641 | 639 | |
| 642 | 640 | /* Sanity check register values ... partially compensating for the |
| 643 | 641 | * fact that SPI has no device handshake. A pullup on MISO would |
| @@ -723,9 +721,7 @@ static int ds1305_probe(struct spi_device *spi) · 79 unmodified lines | ||
| 723 | 721 | goto fail0; |
| 724 | 722 | } |
| 725 | 723 | |
| 726 | − dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", | |
| 727 | − "write", ds1305->ctrl[0], | |
| 728 | − ds1305->ctrl[1], ds1305->ctrl[2]); | |
| 724 | + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl); | |
| 729 | 725 | } |
| 730 | 726 | |
| 731 | 727 | /* see if non-Linux software set up AM/PM mode */ |
| @@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) · 321 unmodified lines | ||
| 322 | 322 | return -EIO; |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | − dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | |
| 326 | − "read", | |
| 327 | − ds1307->regs[0], ds1307->regs[1], | |
| 328 | − ds1307->regs[2], ds1307->regs[3], | |
| 329 | − ds1307->regs[4], ds1307->regs[5], | |
| 330 | − ds1307->regs[6]); | |
| 325 | + dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs); | |
| 331 | 326 | |
| 332 | 327 | t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f); |
| 333 | 328 | t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); |
| @@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) · 64 unmodified lines | ||
| 398 | 393 | break; |
| 399 | 394 | } |
| 400 | 395 | |
| 401 | − dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | |
| 402 | − "write", buf[0], buf[1], buf[2], buf[3], | |
| 403 | − buf[4], buf[5], buf[6]); | |
| 396 | + dev_dbg(dev, "%s: %7ph\n", "write", buf); | |
| 404 | 397 | |
| 405 | 398 | result = ds1307->write_block_data(ds1307->client, |
| 406 | 399 | ds1307->offset, 7, buf); |
| @@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, · 69 unmodified lines | ||
| 70 | 70 | for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { |
| 71 | 71 | err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); |
| 72 | 72 | if (err) { |
| 73 | − printk(KERN_ERR "error mapping gpio %s: %d\n", | |
| 73 | + dev_err(&pdev->dev, "error mapping gpio %s: %d\n", | |
| 74 | 74 | ds2404_gpio[i].name, err); |
| 75 | 75 | goto err_request; |
| 76 | 76 | } |
| @@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset, · 100 unmodified lines | ||
| 177 | 177 | |
| 178 | 178 | for (i = 0; i < length; i++) { |
| 179 | 179 | if (out[i] != ds2404_read_byte(dev)) { |
| 180 | − printk(KERN_ERR "read invalid data\n"); | |
| 180 | + dev_err(dev, "read invalid data\n"); | |
| 181 | 181 | return; |
| 182 | 182 | } |
| 183 | 183 | } |
| @@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = { · 99 unmodified lines | ||
| 283 | 283 | .owner = THIS_MODULE, |
| 284 | 284 | }, |
| 285 | 285 | }; |
| 286 | − | |
| 287 | −static __init int ds2404_init(void) | |
| 288 | −{ | |
| 289 | − return platform_driver_register(&rtc_device_driver); | |
| 290 | −} | |
| 291 | − | |
| 292 | −static __exit void ds2404_exit(void) | |
| 293 | −{ | |
| 294 | − platform_driver_unregister(&rtc_device_driver); | |
| 295 | −} | |
| 296 | − | |
| 297 | −module_init(ds2404_init); | |
| 298 | −module_exit(ds2404_exit); | |
| 286 | +module_platform_driver(rtc_device_driver); | |
| 299 | 287 | |
| 300 | 288 | MODULE_DESCRIPTION("DS2404 RTC"); |
| 301 | 289 | MODULE_AUTHOR("Sven Schnelle"); |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | * |
| 14 | 14 | */ |
| 15 | 15 | |
| 16 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 17 | + | |
| 16 | 18 | #include <linux/kernel.h> |
| 17 | 19 | #include <linux/module.h> |
| 18 | 20 | #include <linux/time.h> |
| @@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft) · 28 unmodified lines | ||
| 47 | 49 | int ndays = 0; |
| 48 | 50 | |
| 49 | 51 | if (eft->year < 1998) { |
| 50 | − printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); | |
| 52 | + pr_err("EFI year < 1998, invalid date\n"); | |
| 51 | 53 | return -1; |
| 52 | 54 | } |
| 53 | 55 | |
| @@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) · 16 unmodified lines | ||
| 70 | 72 | eft->day = wtime->tm_mday; |
| 71 | 73 | eft->hour = wtime->tm_hour; |
| 72 | 74 | eft->minute = wtime->tm_min; |
| 73 | − eft->second = wtime->tm_sec; | |
| 75 | + eft->second = wtime->tm_sec; | |
| 74 | 76 | eft->nanosecond = 0; |
| 75 | 77 | eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; |
| 76 | 78 | eft->timezone = EFI_UNSPECIFIED_TIMEZONE; |
| @@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) · 65 unmodified lines | ||
| 142 | 144 | */ |
| 143 | 145 | status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); |
| 144 | 146 | |
| 145 | − printk(KERN_WARNING "write status is %d\n", (int)status); | |
| 147 | + dev_warn(dev, "write status is %d\n", (int)status); | |
| 146 | 148 | |
| 147 | 149 | return status == EFI_SUCCESS ? 0 : -EINVAL; |
| 148 | 150 | } |
| @@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm) · 8 unmodified lines | ||
| 157 | 159 | |
| 158 | 160 | if (status != EFI_SUCCESS) { |
| 159 | 161 | /* should never happen */ |
| 160 | − printk(KERN_ERR "efitime: can't read time\n"); | |
| 162 | + dev_err(dev, "can't read time\n"); | |
| 161 | 163 | return -EINVAL; |
| 162 | 164 | } |
| 163 | 165 | |
| @@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) · 115 unmodified lines | ||
| 116 | 116 | |
| 117 | 117 | fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); |
| 118 | 118 | |
| 119 | − dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" | |
| 120 | − "%02x %02x %02x %02x %02x %02x %02x\n", | |
| 121 | − "read", | |
| 122 | − fm3130->regs[0], fm3130->regs[1], | |
| 123 | − fm3130->regs[2], fm3130->regs[3], | |
| 124 | − fm3130->regs[4], fm3130->regs[5], | |
| 125 | − fm3130->regs[6], fm3130->regs[7], | |
| 126 | − fm3130->regs[8], fm3130->regs[9], | |
| 127 | − fm3130->regs[0xa], fm3130->regs[0xb], | |
| 128 | − fm3130->regs[0xc], fm3130->regs[0xd], | |
| 129 | − fm3130->regs[0xe]); | |
| 119 | + dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs); | |
| 130 | 120 | |
| 131 | 121 | t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); |
| 132 | 122 | t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); |
| @@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t) · 42 unmodified lines | ||
| 175 | 165 | tmp = t->tm_year - 100; |
| 176 | 166 | buf[FM3130_RTC_YEARS] = bin2bcd(tmp); |
| 177 | 167 | |
| 178 | − dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x" | |
| 179 | − "%02x %02x %02x %02x %02x %02x %02x %02x\n", | |
| 180 | − "write", buf[0], buf[1], buf[2], buf[3], | |
| 181 | − buf[4], buf[5], buf[6], buf[7], | |
| 182 | − buf[8], buf[9], buf[0xa], buf[0xb], | |
| 183 | − buf[0xc], buf[0xd], buf[0xe]); | |
| 168 | + dev_dbg(dev, "%s: %15ph\n", "write", buf); | |
| 184 | 169 | |
| 185 | 170 | fm3130_rtc_mode(dev, FM3130_MODE_WRITE); |
| 186 | 171 | |
| @@ -517,18 +502,8 @@ bad_alarm: · 330 unmodified lines | ||
| 517 | 502 | bad_clock: |
| 518 | 503 | |
| 519 | 504 | if (!fm3130->data_valid || !fm3130->alarm_valid) |
| 520 | − dev_dbg(&client->dev, | |
| 521 | − "%s: %02x %02x %02x %02x %02x %02x %02x %02x" | |
| 522 | − "%02x %02x %02x %02x %02x %02x %02x\n", | |
| 523 | − "bogus registers", | |
| 524 | − fm3130->regs[0], fm3130->regs[1], | |
| 525 | − fm3130->regs[2], fm3130->regs[3], | |
| 526 | − fm3130->regs[4], fm3130->regs[5], | |
| 527 | − fm3130->regs[6], fm3130->regs[7], | |
| 528 | − fm3130->regs[8], fm3130->regs[9], | |
| 529 | − fm3130->regs[0xa], fm3130->regs[0xb], | |
| 530 | − fm3130->regs[0xc], fm3130->regs[0xd], | |
| 531 | − fm3130->regs[0xe]); | |
| 505 | + dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers", | |
| 506 | + fm3130->regs); | |
| 532 | 507 | |
| 533 | 508 | /* We won't bail out here because we just got invalid data. |
| 534 | 509 | Time setting from u-boot doesn't work anyway */ |
| @@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev) · 405 unmodified lines | ||
| 406 | 406 | |
| 407 | 407 | mutex_init(&imxdi->write_mutex); |
| 408 | 408 | |
| 409 | − imxdi->clk = clk_get(&pdev->dev, NULL); | |
| 409 | + imxdi->clk = devm_clk_get(&pdev->dev, NULL); | |
| 410 | 410 | if (IS_ERR(imxdi->clk)) |
| 411 | 411 | return PTR_ERR(imxdi->clk); |
| 412 | 412 | clk_prepare_enable(imxdi->clk); |
| @@ -475,7 +475,6 @@ static int dryice_rtc_probe(struct platform_device *pdev) · 62 unmodified lines | ||
| 475 | 475 | |
| 476 | 476 | err: |
| 477 | 477 | clk_disable_unprepare(imxdi->clk); |
| 478 | − clk_put(imxdi->clk); | |
| 479 | 478 | |
| 480 | 479 | return rc; |
| 481 | 480 | } |
| @@ -492,7 +491,6 @@ static int dryice_rtc_remove(struct platform_device *pdev) · 10 unmodified lines | ||
| 492 | 491 | rtc_device_unregister(imxdi->rtc); |
| 493 | 492 | |
| 494 | 493 | clk_disable_unprepare(imxdi->clk); |
| 495 | − clk_put(imxdi->clk); | |
| 496 | 494 | |
| 497 | 495 | return 0; |
| 498 | 496 | } |
| @@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) · 226 unmodified lines | ||
| 227 | 227 | buf[ISL12022_REG_SC + i]); |
| 228 | 228 | if (ret) |
| 229 | 229 | return -EIO; |
| 230 | − }; | |
| 230 | + } | |
| 231 | 231 | |
| 232 | 232 | return 0; |
| 233 | 233 | } |
| @@ -0,0 +1,338 @@ | ||
| 1 | +/* | |
| 2 | + * TI LP8788 MFD - rtc driver | |
| 3 | + * | |
| 4 | + * Copyright 2012 Texas Instruments | |
| 5 | + * | |
| 6 | + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + * | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/err.h> | |
| 15 | +#include <linux/irqdomain.h> | |
| 16 | +#include <linux/mfd/lp8788.h> | |
| 17 | +#include <linux/module.h> | |
| 18 | +#include <linux/platform_device.h> | |
| 19 | +#include <linux/rtc.h> | |
| 20 | +#include <linux/slab.h> | |
| 21 | + | |
| 22 | +/* register address */ | |
| 23 | +#define LP8788_INTEN_3 0x05 | |
| 24 | +#define LP8788_RTC_UNLOCK 0x64 | |
| 25 | +#define LP8788_RTC_SEC 0x70 | |
| 26 | +#define LP8788_ALM1_SEC 0x77 | |
| 27 | +#define LP8788_ALM1_EN 0x7D | |
| 28 | +#define LP8788_ALM2_SEC 0x7E | |
| 29 | +#define LP8788_ALM2_EN 0x84 | |
| 30 | + | |
| 31 | +/* mask/shift bits */ | |
| 32 | +#define LP8788_INT_RTC_ALM1_M BIT(1) /* Addr 05h */ | |
| 33 | +#define LP8788_INT_RTC_ALM1_S 1 | |
| 34 | +#define LP8788_INT_RTC_ALM2_M BIT(2) /* Addr 05h */ | |
| 35 | +#define LP8788_INT_RTC_ALM2_S 2 | |
| 36 | +#define LP8788_ALM_EN_M BIT(7) /* Addr 7Dh or 84h */ | |
| 37 | +#define LP8788_ALM_EN_S 7 | |
| 38 | + | |
| 39 | +#define DEFAULT_ALARM_SEL LP8788_ALARM_1 | |
| 40 | +#define LP8788_MONTH_OFFSET 1 | |
| 41 | +#define LP8788_BASE_YEAR 2000 | |
| 42 | +#define MAX_WDAY_BITS 7 | |
| 43 | +#define LP8788_WDAY_SET 1 | |
| 44 | +#define RTC_UNLOCK 0x1 | |
| 45 | +#define RTC_LATCH 0x2 | |
| 46 | +#define ALARM_IRQ_FLAG (RTC_IRQF | RTC_AF) | |
| 47 | + | |
| 48 | +enum lp8788_time { | |
| 49 | + LPTIME_SEC, | |
| 50 | + LPTIME_MIN, | |
| 51 | + LPTIME_HOUR, | |
| 52 | + LPTIME_MDAY, | |
| 53 | + LPTIME_MON, | |
| 54 | + LPTIME_YEAR, | |
| 55 | + LPTIME_WDAY, | |
| 56 | + LPTIME_MAX, | |
| 57 | +}; | |
| 58 | + | |
| 59 | +struct lp8788_rtc { | |
| 60 | + struct lp8788 *lp; | |
| 61 | + struct rtc_device *rdev; | |
| 62 | + enum lp8788_alarm_sel alarm; | |
| 63 | + int irq; | |
| 64 | +}; | |
| 65 | + | |
| 66 | +static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = { | |
| 67 | + LP8788_ALM1_SEC, | |
| 68 | + LP8788_ALM2_SEC, | |
| 69 | +}; | |
| 70 | + | |
| 71 | +static const u8 addr_alarm_en[LP8788_ALARM_MAX] = { | |
| 72 | + LP8788_ALM1_EN, | |
| 73 | + LP8788_ALM2_EN, | |
| 74 | +}; | |
| 75 | + | |
| 76 | +static const u8 mask_alarm_en[LP8788_ALARM_MAX] = { | |
| 77 | + LP8788_INT_RTC_ALM1_M, | |
| 78 | + LP8788_INT_RTC_ALM2_M, | |
| 79 | +}; | |
| 80 | + | |
| 81 | +static const u8 shift_alarm_en[LP8788_ALARM_MAX] = { | |
| 82 | + LP8788_INT_RTC_ALM1_S, | |
| 83 | + LP8788_INT_RTC_ALM2_S, | |
| 84 | +}; | |
| 85 | + | |
| 86 | +static int _to_tm_wday(u8 lp8788_wday) | |
| 87 | +{ | |
| 88 | + int i; | |
| 89 | + | |
| 90 | + if (lp8788_wday == 0) | |
| 91 | + return 0; | |
| 92 | + | |
| 93 | + /* lookup defined weekday from read register value */ | |
| 94 | + for (i = 0; i < MAX_WDAY_BITS; i++) { | |
| 95 | + if ((lp8788_wday >> i) == LP8788_WDAY_SET) | |
| 96 | + break; | |
| 97 | + } | |
| 98 | + | |
| 99 | + return i + 1; | |
| 100 | +} | |
| 101 | + | |
| 102 | +static inline int _to_lp8788_wday(int tm_wday) | |
| 103 | +{ | |
| 104 | + return LP8788_WDAY_SET << (tm_wday - 1); | |
| 105 | +} | |
| 106 | + | |
| 107 | +static void lp8788_rtc_unlock(struct lp8788 *lp) | |
| 108 | +{ | |
| 109 | + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK); | |
| 110 | + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH); | |
| 111 | +} | |
| 112 | + | |
| 113 | +static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
| 114 | +{ | |
| 115 | + struct lp8788_rtc *rtc = dev_get_drvdata(dev); | |
| 116 | + struct lp8788 *lp = rtc->lp; | |
| 117 | + u8 data[LPTIME_MAX]; | |
| 118 | + int ret; | |
| 119 | + | |
| 120 | + lp8788_rtc_unlock(lp); | |
| 121 | + | |
| 122 | + ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data, LPTIME_MAX); | |
| 123 | + if (ret) | |
| 124 | + return ret; | |
| 125 | + | |
| 126 | + tm->tm_sec = data[LPTIME_SEC]; | |
| 127 | + tm->tm_min = data[LPTIME_MIN]; | |
| 128 | + tm->tm_hour = data[LPTIME_HOUR]; | |
| 129 | + tm->tm_mday = data[LPTIME_MDAY]; | |
| 130 | + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; | |
| 131 | + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; | |
| 132 | + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); | |
| 133 | + | |
| 134 | + return 0; | |
| 135 | +} | |
| 136 | + | |
| 137 | +static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
| 138 | +{ | |
| 139 | + struct lp8788_rtc *rtc = dev_get_drvdata(dev); | |
| 140 | + struct lp8788 *lp = rtc->lp; | |
| 141 | + u8 data[LPTIME_MAX - 1]; | |
| 142 | + int ret, i, year; | |
| 143 | + | |
| 144 | + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; | |
| 145 | + if (year < 0) { | |
| 146 | + dev_err(lp->dev, "invalid year: %d\n", year); | |
| 147 | + return -EINVAL; | |
| 148 | + } | |
| 149 | + | |
| 150 | + /* because rtc weekday is a readonly register, do not update */ | |
| 151 | + data[LPTIME_SEC] = tm->tm_sec; | |
| 152 | + data[LPTIME_MIN] = tm->tm_min; | |
| 153 | + data[LPTIME_HOUR] = tm->tm_hour; | |
| 154 | + data[LPTIME_MDAY] = tm->tm_mday; | |
| 155 | + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; | |
| 156 | + data[LPTIME_YEAR] = year; | |
| 157 | + | |
| 158 | + for (i = 0; i < ARRAY_SIZE(data); i++) { | |
| 159 | + ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]); | |
| 160 | + if (ret) | |
| 161 | + return ret; | |
| 162 | + } | |
| 163 | + | |
| 164 | + return 0; | |
| 165 | +} | |
| 166 | + | |
| 167 | +static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
| 168 | +{ | |
| 169 | + struct lp8788_rtc *rtc = dev_get_drvdata(dev); | |
| 170 | + struct lp8788 *lp = rtc->lp; | |
| 171 | + struct rtc_time *tm = &alarm->time; | |
| 172 | + u8 addr, data[LPTIME_MAX]; | |
| 173 | + int ret; | |
| 174 | + | |
| 175 | + addr = addr_alarm_sec[rtc->alarm]; | |
| 176 | + ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX); | |
| 177 | + if (ret) | |
| 178 | + return ret; | |
| 179 | + | |
| 180 | + tm->tm_sec = data[LPTIME_SEC]; | |
| 181 | + tm->tm_min = data[LPTIME_MIN]; | |
| 182 | + tm->tm_hour = data[LPTIME_HOUR]; | |
| 183 | + tm->tm_mday = data[LPTIME_MDAY]; | |
| 184 | + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; | |
| 185 | + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; | |
| 186 | + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); | |
| 187 | + alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M; | |
| 188 | + | |
| 189 | + return 0; | |
| 190 | +} | |
| 191 | + | |
| 192 | +static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
| 193 | +{ | |
| 194 | + struct lp8788_rtc *rtc = dev_get_drvdata(dev); | |
| 195 | + struct lp8788 *lp = rtc->lp; | |
| 196 | + struct rtc_time *tm = &alarm->time; | |
| 197 | + u8 addr, data[LPTIME_MAX]; | |
| 198 | + int ret, i, year; | |
| 199 | + | |
| 200 | + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; | |
| 201 | + if (year < 0) { | |
| 202 | + dev_err(lp->dev, "invalid year: %d\n", year); | |
| 203 | + return -EINVAL; | |
| 204 | + } | |
| 205 | + | |
| 206 | + data[LPTIME_SEC] = tm->tm_sec; | |
| 207 | + data[LPTIME_MIN] = tm->tm_min; | |
| 208 | + data[LPTIME_HOUR] = tm->tm_hour; | |
| 209 | + data[LPTIME_MDAY] = tm->tm_mday; | |
| 210 | + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; | |
| 211 | + data[LPTIME_YEAR] = year; | |
| 212 | + data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday); | |
| 213 | + | |
| 214 | + for (i = 0; i < ARRAY_SIZE(data); i++) { | |
| 215 | + addr = addr_alarm_sec[rtc->alarm] + i; | |
| 216 | + ret = lp8788_write_byte(lp, addr, data[i]); | |
| 217 | + if (ret) | |
| 218 | + return ret; | |
| 219 | + } | |
| 220 | + | |
| 221 | + alarm->enabled = 1; | |
| 222 | + addr = addr_alarm_en[rtc->alarm]; | |
| 223 | + | |
| 224 | + return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M, | |
| 225 | + alarm->enabled << LP8788_ALM_EN_S); | |
| 226 | +} | |
| 227 | + | |
| 228 | +static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable) | |
| 229 | +{ | |
| 230 | + struct lp8788_rtc *rtc = dev_get_drvdata(dev); | |
| 231 | + struct lp8788 *lp = rtc->lp; | |
| 232 | + u8 mask, shift; | |
| 233 | + | |
| 234 | + if (!rtc->irq) | |
| 235 | + return -EIO; | |
| 236 | + | |
| 237 | + mask = mask_alarm_en[rtc->alarm]; | |
| 238 | + shift = shift_alarm_en[rtc->alarm]; | |
| 239 | + | |
| 240 | + return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift); | |
| 241 | +} | |
| 242 | + | |
| 243 | +static const struct rtc_class_ops lp8788_rtc_ops = { | |
| 244 | + .read_time = lp8788_rtc_read_time, | |
| 245 | + .set_time = lp8788_rtc_set_time, | |
| 246 | + .read_alarm = lp8788_read_alarm, | |
| 247 | + .set_alarm = lp8788_set_alarm, | |
| 248 | + .alarm_irq_enable = lp8788_alarm_irq_enable, | |
| 249 | +}; | |
| 250 | + | |
| 251 | +static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr) | |
| 252 | +{ | |
| 253 | + struct lp8788_rtc *rtc = ptr; | |
| 254 | + | |
| 255 | + rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG); | |
| 256 | + return IRQ_HANDLED; | |
| 257 | +} | |
| 258 | + | |
| 259 | +static int lp8788_alarm_irq_register(struct platform_device *pdev, | |
| 260 | + struct lp8788_rtc *rtc) | |
| 261 | +{ | |
| 262 | + struct resource *r; | |
| 263 | + struct lp8788 *lp = rtc->lp; | |
| 264 | + struct irq_domain *irqdm = lp->irqdm; | |
| 265 | + int irq; | |
| 266 | + | |
| 267 | + rtc->irq = 0; | |
| 268 | + | |
| 269 | + /* even the alarm IRQ number is not specified, rtc time should work */ | |
| 270 | + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ); | |
| 271 | + if (!r) | |
| 272 | + return 0; | |
| 273 | + | |
| 274 | + if (rtc->alarm == LP8788_ALARM_1) | |
| 275 | + irq = r->start; | |
| 276 | + else | |
| 277 | + irq = r->end; | |
| 278 | + | |
| 279 | + rtc->irq = irq_create_mapping(irqdm, irq); | |
| 280 | + | |
| 281 | + return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | |
| 282 | + lp8788_alarm_irq_handler, | |
| 283 | + 0, LP8788_ALM_IRQ, rtc); | |
| 284 | +} | |
| 285 | + | |
| 286 | +static int lp8788_rtc_probe(struct platform_device *pdev) | |
| 287 | +{ | |
| 288 | + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); | |
| 289 | + struct lp8788_rtc *rtc; | |
| 290 | + struct device *dev = &pdev->dev; | |
| 291 | + | |
| 292 | + rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL); | |
| 293 | + if (!rtc) | |
| 294 | + return -ENOMEM; | |
| 295 | + | |
| 296 | + rtc->lp = lp; | |
| 297 | + rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL; | |
| 298 | + platform_set_drvdata(pdev, rtc); | |
| 299 | + | |
| 300 | + device_init_wakeup(dev, 1); | |
| 301 | + | |
| 302 | + rtc->rdev = rtc_device_register("lp8788_rtc", dev, | |
| 303 | + &lp8788_rtc_ops, THIS_MODULE); | |
| 304 | + if (IS_ERR(rtc->rdev)) { | |
| 305 | + dev_err(dev, "can not register rtc device\n"); | |
| 306 | + return PTR_ERR(rtc->rdev); | |
| 307 | + } | |
| 308 | + | |
| 309 | + if (lp8788_alarm_irq_register(pdev, rtc)) | |
| 310 | + dev_warn(lp->dev, "no rtc irq handler\n"); | |
| 311 | + | |
| 312 | + return 0; | |
| 313 | +} | |
| 314 | + | |
| 315 | +static int lp8788_rtc_remove(struct platform_device *pdev) | |
| 316 | +{ | |
| 317 | + struct lp8788_rtc *rtc = platform_get_drvdata(pdev); | |
| 318 | + | |
| 319 | + rtc_device_unregister(rtc->rdev); | |
| 320 | + platform_set_drvdata(pdev, NULL); | |
| 321 | + | |
| 322 | + return 0; | |
| 323 | +} | |
| 324 | + | |
| 325 | +static struct platform_driver lp8788_rtc_driver = { | |
| 326 | + .probe = lp8788_rtc_probe, | |
| 327 | + .remove = lp8788_rtc_remove, | |
| 328 | + .driver = { | |
| 329 | + .name = LP8788_DEV_RTC, | |
| 330 | + .owner = THIS_MODULE, | |
| 331 | + }, | |
| 332 | +}; | |
| 333 | +module_platform_driver(lp8788_rtc_driver); | |
| 334 | + | |
| 335 | +MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver"); | |
| 336 | +MODULE_AUTHOR("Milo Kim"); | |
| 337 | +MODULE_LICENSE("GPL"); | |
| 338 | +MODULE_ALIAS("platform:lp8788-rtc"); | |
| @@ -0,0 +1,641 @@ | ||
| 1 | +/* | |
| 2 | + * RTC driver for Maxim MAX77686 | |
| 3 | + * | |
| 4 | + * Copyright (C) 2012 Samsung Electronics Co.Ltd | |
| 5 | + * | |
| 6 | + * based on rtc-max8997.c | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + */ | |
| 14 | + | |
| 15 | +#include <linux/slab.h> | |
| 16 | +#include <linux/rtc.h> | |
| 17 | +#include <linux/delay.h> | |
| 18 | +#include <linux/mutex.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/platform_device.h> | |
| 21 | +#include <linux/mfd/max77686-private.h> | |
| 22 | +#include <linux/irqdomain.h> | |
| 23 | +#include <linux/regmap.h> | |
| 24 | + | |
| 25 | +/* RTC Control Register */ | |
| 26 | +#define BCD_EN_SHIFT 0 | |
| 27 | +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) | |
| 28 | +#define MODEL24_SHIFT 1 | |
| 29 | +#define MODEL24_MASK (1 << MODEL24_SHIFT) | |
| 30 | +/* RTC Update Register1 */ | |
| 31 | +#define RTC_UDR_SHIFT 0 | |
| 32 | +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) | |
| 33 | +#define RTC_RBUDR_SHIFT 4 | |
| 34 | +#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) | |
| 35 | +/* WTSR and SMPL Register */ | |
| 36 | +#define WTSRT_SHIFT 0 | |
| 37 | +#define SMPLT_SHIFT 2 | |
| 38 | +#define WTSR_EN_SHIFT 6 | |
| 39 | +#define SMPL_EN_SHIFT 7 | |
| 40 | +#define WTSRT_MASK (3 << WTSRT_SHIFT) | |
| 41 | +#define SMPLT_MASK (3 << SMPLT_SHIFT) | |
| 42 | +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) | |
| 43 | +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) | |
| 44 | +/* RTC Hour register */ | |
| 45 | +#define HOUR_PM_SHIFT 6 | |
| 46 | +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) | |
| 47 | +/* RTC Alarm Enable */ | |
| 48 | +#define ALARM_ENABLE_SHIFT 7 | |
| 49 | +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) | |
| 50 | + | |
| 51 | +#define MAX77686_RTC_UPDATE_DELAY 16 | |
| 52 | +#undef MAX77686_RTC_WTSR_SMPL | |
| 53 | + | |
| 54 | +enum { | |
| 55 | + RTC_SEC = 0, | |
| 56 | + RTC_MIN, | |
| 57 | + RTC_HOUR, | |
| 58 | + RTC_WEEKDAY, | |
| 59 | + RTC_MONTH, | |
| 60 | + RTC_YEAR, | |
| 61 | + RTC_DATE, | |
| 62 | + RTC_NR_TIME | |
| 63 | +}; | |
| 64 | + | |
| 65 | +struct max77686_rtc_info { | |
| 66 | + struct device *dev; | |
| 67 | + struct max77686_dev *max77686; | |
| 68 | + struct i2c_client *rtc; | |
| 69 | + struct rtc_device *rtc_dev; | |
| 70 | + struct mutex lock; | |
| 71 | + | |
| 72 | + struct regmap *regmap; | |
| 73 | + | |
| 74 | + int virq; | |
| 75 | + int rtc_24hr_mode; | |
| 76 | +}; | |
| 77 | + | |
| 78 | +enum MAX77686_RTC_OP { | |
| 79 | + MAX77686_RTC_WRITE, | |
| 80 | + MAX77686_RTC_READ, | |
| 81 | +}; | |
| 82 | + | |
| 83 | +static inline int max77686_rtc_calculate_wday(u8 shifted) | |
| 84 | +{ | |
| 85 | + int counter = -1; | |
| 86 | + while (shifted) { | |
| 87 | + shifted >>= 1; | |
| 88 | + counter++; | |
| 89 | + } | |
| 90 | + return counter; | |
| 91 | +} | |
| 92 | + | |
| 93 | +static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, | |
| 94 | + int rtc_24hr_mode) | |
| 95 | +{ | |
| 96 | + tm->tm_sec = data[RTC_SEC] & 0x7f; | |
| 97 | + tm->tm_min = data[RTC_MIN] & 0x7f; | |
| 98 | + if (rtc_24hr_mode) | |
| 99 | + tm->tm_hour = data[RTC_HOUR] & 0x1f; | |
| 100 | + else { | |
| 101 | + tm->tm_hour = data[RTC_HOUR] & 0x0f; | |
| 102 | + if (data[RTC_HOUR] & HOUR_PM_MASK) | |
| 103 | + tm->tm_hour += 12; | |
| 104 | + } | |
| 105 | + | |
| 106 | + tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f); | |
| 107 | + tm->tm_mday = data[RTC_DATE] & 0x1f; | |
| 108 | + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; | |
| 109 | + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; | |
| 110 | + tm->tm_yday = 0; | |
| 111 | + tm->tm_isdst = 0; | |
| 112 | +} | |
| 113 | + | |
| 114 | +static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) | |
| 115 | +{ | |
| 116 | + data[RTC_SEC] = tm->tm_sec; | |
| 117 | + data[RTC_MIN] = tm->tm_min; | |
| 118 | + data[RTC_HOUR] = tm->tm_hour; | |
| 119 | + data[RTC_WEEKDAY] = 1 << tm->tm_wday; | |
| 120 | + data[RTC_DATE] = tm->tm_mday; | |
| 121 | + data[RTC_MONTH] = tm->tm_mon + 1; | |
| 122 | + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; | |
| 123 | + | |
| 124 | + if (tm->tm_year < 100) { | |
| 125 | + pr_warn("%s: MAX77686 RTC cannot handle the year %d." | |
| 126 | + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); | |
| 127 | + return -EINVAL; | |
| 128 | + } | |
| 129 | + return 0; | |
| 130 | +} | |
| 131 | + | |
| 132 | +static int max77686_rtc_update(struct max77686_rtc_info *info, | |
| 133 | + enum MAX77686_RTC_OP op) | |
| 134 | +{ | |
| 135 | + int ret; | |
| 136 | + unsigned int data; | |
| 137 | + | |
| 138 | + if (op == MAX77686_RTC_WRITE) | |
| 139 | + data = 1 << RTC_UDR_SHIFT; | |
| 140 | + else | |
| 141 | + data = 1 << RTC_RBUDR_SHIFT; | |
| 142 | + | |
| 143 | + ret = regmap_update_bits(info->max77686->rtc_regmap, | |
| 144 | + MAX77686_RTC_UPDATE0, data, data); | |
| 145 | + if (ret < 0) | |
| 146 | + dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", | |
| 147 | + __func__, ret, data); | |
| 148 | + else { | |
| 149 | + /* Minimum 16ms delay required before RTC update. */ | |
| 150 | + msleep(MAX77686_RTC_UPDATE_DELAY); | |
| 151 | + } | |
| 152 | + | |
| 153 | + return ret; | |
| 154 | +} | |
| 155 | + | |
| 156 | +static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
| 157 | +{ | |
| 158 | + struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
| 159 | + u8 data[RTC_NR_TIME]; | |
| 160 | + int ret; | |
| 161 | + | |
| 162 | + mutex_lock(&info->lock); | |
| 163 | + | |
| 164 | + ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
| 165 | + if (ret < 0) | |
| 166 | + goto out; | |
| 167 | + | |
| 168 | + ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
| 169 | + MAX77686_RTC_SEC, data, RTC_NR_TIME); | |
| 170 | + if (ret < 0) { | |
| 171 | + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); | |
| 172 | + goto out; | |
| 173 | + } | |
| 174 | + | |
| 175 | + max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); | |
| 176 | + | |
| 177 | + ret = rtc_valid_tm(tm); | |
| 178 | + | |
| 179 | +out: | |
| 180 | + mutex_unlock(&info->lock); | |
| 181 | + return ret; | |
| 182 | +} | |
| 183 | + | |
| 184 | +static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
| 185 | +{ | |
| 186 | + struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
| 187 | + u8 data[RTC_NR_TIME]; | |
| 188 | + int ret; | |
| 189 | + | |
| 190 | + ret = max77686_rtc_tm_to_data(tm, data); | |
| 191 | + if (ret < 0) | |
| 192 | + return ret; | |
| 193 | + | |
| 194 | + mutex_lock(&info->lock); | |
| 195 | + | |
| 196 | + ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
| 197 | + MAX77686_RTC_SEC, data, RTC_NR_TIME); | |
| 198 | + if (ret < 0) { | |
| 199 | + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, | |
| 200 | + ret); | |
| 201 | + goto out; | |
| 202 | + } | |
| 203 | + | |
| 204 | + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 205 | + | |
| 206 | +out: | |
| 207 | + mutex_unlock(&info->lock); | |
| 208 | + return ret; | |
| 209 | +} | |
| 210 | + | |
| 211 | +static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 212 | +{ | |
| 213 | + struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
| 214 | + u8 data[RTC_NR_TIME]; | |
| 215 | + unsigned int val; | |
| 216 | + int i, ret; | |
| 217 | + | |
| 218 | + mutex_lock(&info->lock); | |
| 219 | + | |
| 220 | + ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
| 221 | + if (ret < 0) | |
| 222 | + goto out; | |
| 223 | + | |
| 224 | + ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
| 225 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 226 | + if (ret < 0) { | |
| 227 | + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", | |
| 228 | + __func__, __LINE__, ret); | |
| 229 | + goto out; | |
| 230 | + } | |
| 231 | + | |
| 232 | + max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); | |
| 233 | + | |
| 234 | + alrm->enabled = 0; | |
| 235 | + for (i = 0; i < RTC_NR_TIME; i++) { | |
| 236 | + if (data[i] & ALARM_ENABLE_MASK) { | |
| 237 | + alrm->enabled = 1; | |
| 238 | + break; | |
| 239 | + } | |
| 240 | + } | |
| 241 | + | |
| 242 | + alrm->pending = 0; | |
| 243 | + ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val); | |
| 244 | + if (ret < 0) { | |
| 245 | + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", | |
| 246 | + __func__, __LINE__, ret); | |
| 247 | + goto out; | |
| 248 | + } | |
| 249 | + | |
| 250 | + if (val & (1 << 4)) /* RTCA1 */ | |
| 251 | + alrm->pending = 1; | |
| 252 | + | |
| 253 | +out: | |
| 254 | + mutex_unlock(&info->lock); | |
| 255 | + return 0; | |
| 256 | +} | |
| 257 | + | |
| 258 | +static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) | |
| 259 | +{ | |
| 260 | + u8 data[RTC_NR_TIME]; | |
| 261 | + int ret, i; | |
| 262 | + struct rtc_time tm; | |
| 263 | + | |
| 264 | + if (!mutex_is_locked(&info->lock)) | |
| 265 | + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
| 266 | + | |
| 267 | + ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
| 268 | + if (ret < 0) | |
| 269 | + goto out; | |
| 270 | + | |
| 271 | + ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
| 272 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 273 | + if (ret < 0) { | |
| 274 | + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", | |
| 275 | + __func__, ret); | |
| 276 | + goto out; | |
| 277 | + } | |
| 278 | + | |
| 279 | + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); | |
| 280 | + | |
| 281 | + for (i = 0; i < RTC_NR_TIME; i++) | |
| 282 | + data[i] &= ~ALARM_ENABLE_MASK; | |
| 283 | + | |
| 284 | + ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
| 285 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 286 | + if (ret < 0) { | |
| 287 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 288 | + __func__, ret); | |
| 289 | + goto out; | |
| 290 | + } | |
| 291 | + | |
| 292 | + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 293 | +out: | |
| 294 | + return ret; | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) | |
| 298 | +{ | |
| 299 | + u8 data[RTC_NR_TIME]; | |
| 300 | + int ret; | |
| 301 | + struct rtc_time tm; | |
| 302 | + | |
| 303 | + if (!mutex_is_locked(&info->lock)) | |
| 304 | + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
| 305 | + | |
| 306 | + ret = max77686_rtc_update(info, MAX77686_RTC_READ); | |
| 307 | + if (ret < 0) | |
| 308 | + goto out; | |
| 309 | + | |
| 310 | + ret = regmap_bulk_read(info->max77686->rtc_regmap, | |
| 311 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 312 | + if (ret < 0) { | |
| 313 | + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", | |
| 314 | + __func__, ret); | |
| 315 | + goto out; | |
| 316 | + } | |
| 317 | + | |
| 318 | + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); | |
| 319 | + | |
| 320 | + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); | |
| 321 | + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); | |
| 322 | + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); | |
| 323 | + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; | |
| 324 | + if (data[RTC_MONTH] & 0xf) | |
| 325 | + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); | |
| 326 | + if (data[RTC_YEAR] & 0x7f) | |
| 327 | + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); | |
| 328 | + if (data[RTC_DATE] & 0x1f) | |
| 329 | + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); | |
| 330 | + | |
| 331 | + ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
| 332 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 333 | + if (ret < 0) { | |
| 334 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 335 | + __func__, ret); | |
| 336 | + goto out; | |
| 337 | + } | |
| 338 | + | |
| 339 | + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 340 | +out: | |
| 341 | + return ret; | |
| 342 | +} | |
| 343 | + | |
| 344 | +static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 345 | +{ | |
| 346 | + struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
| 347 | + u8 data[RTC_NR_TIME]; | |
| 348 | + int ret; | |
| 349 | + | |
| 350 | + ret = max77686_rtc_tm_to_data(&alrm->time, data); | |
| 351 | + if (ret < 0) | |
| 352 | + return ret; | |
| 353 | + | |
| 354 | + mutex_lock(&info->lock); | |
| 355 | + | |
| 356 | + ret = max77686_rtc_stop_alarm(info); | |
| 357 | + if (ret < 0) | |
| 358 | + goto out; | |
| 359 | + | |
| 360 | + ret = regmap_bulk_write(info->max77686->rtc_regmap, | |
| 361 | + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); | |
| 362 | + | |
| 363 | + if (ret < 0) { | |
| 364 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 365 | + __func__, ret); | |
| 366 | + goto out; | |
| 367 | + } | |
| 368 | + | |
| 369 | + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 370 | + if (ret < 0) | |
| 371 | + goto out; | |
| 372 | + | |
| 373 | + if (alrm->enabled) | |
| 374 | + ret = max77686_rtc_start_alarm(info); | |
| 375 | +out: | |
| 376 | + mutex_unlock(&info->lock); | |
| 377 | + return ret; | |
| 378 | +} | |
| 379 | + | |
| 380 | +static int max77686_rtc_alarm_irq_enable(struct device *dev, | |
| 381 | + unsigned int enabled) | |
| 382 | +{ | |
| 383 | + struct max77686_rtc_info *info = dev_get_drvdata(dev); | |
| 384 | + int ret; | |
| 385 | + | |
| 386 | + mutex_lock(&info->lock); | |
| 387 | + if (enabled) | |
| 388 | + ret = max77686_rtc_start_alarm(info); | |
| 389 | + else | |
| 390 | + ret = max77686_rtc_stop_alarm(info); | |
| 391 | + mutex_unlock(&info->lock); | |
| 392 | + | |
| 393 | + return ret; | |
| 394 | +} | |
| 395 | + | |
| 396 | +static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) | |
| 397 | +{ | |
| 398 | + struct max77686_rtc_info *info = data; | |
| 399 | + | |
| 400 | + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); | |
| 401 | + | |
| 402 | + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); | |
| 403 | + | |
| 404 | + return IRQ_HANDLED; | |
| 405 | +} | |
| 406 | + | |
| 407 | +static const struct rtc_class_ops max77686_rtc_ops = { | |
| 408 | + .read_time = max77686_rtc_read_time, | |
| 409 | + .set_time = max77686_rtc_set_time, | |
| 410 | + .read_alarm = max77686_rtc_read_alarm, | |
| 411 | + .set_alarm = max77686_rtc_set_alarm, | |
| 412 | + .alarm_irq_enable = max77686_rtc_alarm_irq_enable, | |
| 413 | +}; | |
| 414 | + | |
| 415 | +#ifdef MAX77686_RTC_WTSR_SMPL | |
| 416 | +static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable) | |
| 417 | +{ | |
| 418 | + int ret; | |
| 419 | + unsigned int val, mask; | |
| 420 | + | |
| 421 | + if (enable) | |
| 422 | + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); | |
| 423 | + else | |
| 424 | + val = 0; | |
| 425 | + | |
| 426 | + mask = WTSR_EN_MASK | WTSRT_MASK; | |
| 427 | + | |
| 428 | + dev_info(info->dev, "%s: %s WTSR\n", __func__, | |
| 429 | + enable ? "enable" : "disable"); | |
| 430 | + | |
| 431 | + ret = regmap_update_bits(info->max77686->rtc_regmap, | |
| 432 | + MAX77686_WTSR_SMPL_CNTL, mask, val); | |
| 433 | + if (ret < 0) { | |
| 434 | + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", | |
| 435 | + __func__, ret); | |
| 436 | + return; | |
| 437 | + } | |
| 438 | + | |
| 439 | + max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 440 | +} | |
| 441 | + | |
| 442 | +static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable) | |
| 443 | +{ | |
| 444 | + int ret; | |
| 445 | + unsigned int val, mask; | |
| 446 | + | |
| 447 | + if (enable) | |
| 448 | + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); | |
| 449 | + else | |
| 450 | + val = 0; | |
| 451 | + | |
| 452 | + mask = SMPL_EN_MASK | SMPLT_MASK; | |
| 453 | + | |
| 454 | + dev_info(info->dev, "%s: %s SMPL\n", __func__, | |
| 455 | + enable ? "enable" : "disable"); | |
| 456 | + | |
| 457 | + ret = regmap_update_bits(info->max77686->rtc_regmap, | |
| 458 | + MAX77686_WTSR_SMPL_CNTL, mask, val); | |
| 459 | + if (ret < 0) { | |
| 460 | + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", | |
| 461 | + __func__, ret); | |
| 462 | + return; | |
| 463 | + } | |
| 464 | + | |
| 465 | + max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 466 | + | |
| 467 | + val = 0; | |
| 468 | + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); | |
| 469 | + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); | |
| 470 | +} | |
| 471 | +#endif /* MAX77686_RTC_WTSR_SMPL */ | |
| 472 | + | |
| 473 | +static int max77686_rtc_init_reg(struct max77686_rtc_info *info) | |
| 474 | +{ | |
| 475 | + u8 data[2]; | |
| 476 | + int ret; | |
| 477 | + | |
| 478 | + /* Set RTC control register : Binary mode, 24hour mdoe */ | |
| 479 | + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
| 480 | + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
| 481 | + | |
| 482 | + info->rtc_24hr_mode = 1; | |
| 483 | + | |
| 484 | + ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); | |
| 485 | + if (ret < 0) { | |
| 486 | + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", | |
| 487 | + __func__, ret); | |
| 488 | + return ret; | |
| 489 | + } | |
| 490 | + | |
| 491 | + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); | |
| 492 | + return ret; | |
| 493 | +} | |
| 494 | + | |
| 495 | +static struct regmap_config max77686_rtc_regmap_config = { | |
| 496 | + .reg_bits = 8, | |
| 497 | + .val_bits = 8, | |
| 498 | +}; | |
| 499 | + | |
| 500 | +static int max77686_rtc_probe(struct platform_device *pdev) | |
| 501 | +{ | |
| 502 | + struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); | |
| 503 | + struct max77686_rtc_info *info; | |
| 504 | + int ret, virq; | |
| 505 | + | |
| 506 | + dev_info(&pdev->dev, "%s\n", __func__); | |
| 507 | + | |
| 508 | + info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL); | |
| 509 | + if (!info) | |
| 510 | + return -ENOMEM; | |
| 511 | + | |
| 512 | + mutex_init(&info->lock); | |
| 513 | + info->dev = &pdev->dev; | |
| 514 | + info->max77686 = max77686; | |
| 515 | + info->rtc = max77686->rtc; | |
| 516 | + info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc, | |
| 517 | + &max77686_rtc_regmap_config); | |
| 518 | + if (IS_ERR(info->max77686->rtc_regmap)) { | |
| 519 | + ret = PTR_ERR(info->max77686->rtc_regmap); | |
| 520 | + dev_err(info->max77686->dev, "Failed to allocate register map: %d\n", | |
| 521 | + ret); | |
| 522 | + kfree(info); | |
| 523 | + return ret; | |
| 524 | + } | |
| 525 | + platform_set_drvdata(pdev, info); | |
| 526 | + | |
| 527 | + ret = max77686_rtc_init_reg(info); | |
| 528 | + | |
| 529 | + if (ret < 0) { | |
| 530 | + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); | |
| 531 | + goto err_rtc; | |
| 532 | + } | |
| 533 | + | |
| 534 | +#ifdef MAX77686_RTC_WTSR_SMPL | |
| 535 | + max77686_rtc_enable_wtsr(info, true); | |
| 536 | + max77686_rtc_enable_smpl(info, true); | |
| 537 | +#endif | |
| 538 | + | |
| 539 | + device_init_wakeup(&pdev->dev, 1); | |
| 540 | + | |
| 541 | + info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev, | |
| 542 | + &max77686_rtc_ops, THIS_MODULE); | |
| 543 | + | |
| 544 | + if (IS_ERR(info->rtc_dev)) { | |
| 545 | + dev_info(&pdev->dev, "%s: fail\n", __func__); | |
| 546 | + | |
| 547 | + ret = PTR_ERR(info->rtc_dev); | |
| 548 | + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); | |
| 549 | + if (ret == 0) | |
| 550 | + ret = -EINVAL; | |
| 551 | + goto err_rtc; | |
| 552 | + } | |
| 553 | + virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1); | |
| 554 | + if (!virq) | |
| 555 | + goto err_rtc; | |
| 556 | + info->virq = virq; | |
| 557 | + | |
| 558 | + ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0, | |
| 559 | + "rtc-alarm0", info); | |
| 560 | + if (ret < 0) { | |
| 561 | + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", | |
| 562 | + info->virq, ret); | |
| 563 | + goto err_rtc; | |
| 564 | + } | |
| 565 | + | |
| 566 | + goto out; | |
| 567 | +err_rtc: | |
| 568 | + kfree(info); | |
| 569 | + return ret; | |
| 570 | +out: | |
| 571 | + return ret; | |
| 572 | +} | |
| 573 | + | |
| 574 | +static int max77686_rtc_remove(struct platform_device *pdev) | |
| 575 | +{ | |
| 576 | + struct max77686_rtc_info *info = platform_get_drvdata(pdev); | |
| 577 | + | |
| 578 | + if (info) { | |
| 579 | + free_irq(info->virq, info); | |
| 580 | + rtc_device_unregister(info->rtc_dev); | |
| 581 | + kfree(info); | |
| 582 | + } | |
| 583 | + | |
| 584 | + return 0; | |
| 585 | +} | |
| 586 | + | |
| 587 | +static void max77686_rtc_shutdown(struct platform_device *pdev) | |
| 588 | +{ | |
| 589 | +#ifdef MAX77686_RTC_WTSR_SMPL | |
| 590 | + struct max77686_rtc_info *info = platform_get_drvdata(pdev); | |
| 591 | + int i; | |
| 592 | + u8 val = 0; | |
| 593 | + | |
| 594 | + for (i = 0; i < 3; i++) { | |
| 595 | + max77686_rtc_enable_wtsr(info, false); | |
| 596 | + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); | |
| 597 | + pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); | |
| 598 | + if (val & WTSR_EN_MASK) | |
| 599 | + pr_emerg("%s: fail to disable WTSR\n", __func__); | |
| 600 | + else { | |
| 601 | + pr_info("%s: success to disable WTSR\n", __func__); | |
| 602 | + break; | |
| 603 | + } | |
| 604 | + } | |
| 605 | + | |
| 606 | + /* Disable SMPL when power off */ | |
| 607 | + max77686_rtc_enable_smpl(info, false); | |
| 608 | +#endif /* MAX77686_RTC_WTSR_SMPL */ | |
| 609 | +} | |
| 610 | + | |
| 611 | +static const struct platform_device_id rtc_id[] = { | |
| 612 | + { "max77686-rtc", 0 }, | |
| 613 | + {}, | |
| 614 | +}; | |
| 615 | + | |
| 616 | +static struct platform_driver max77686_rtc_driver = { | |
| 617 | + .driver = { | |
| 618 | + .name = "max77686-rtc", | |
| 619 | + .owner = THIS_MODULE, | |
| 620 | + }, | |
| 621 | + .probe = max77686_rtc_probe, | |
| 622 | + .remove = max77686_rtc_remove, | |
| 623 | + .shutdown = max77686_rtc_shutdown, | |
| 624 | + .id_table = rtc_id, | |
| 625 | +}; | |
| 626 | + | |
| 627 | +static int __init max77686_rtc_init(void) | |
| 628 | +{ | |
| 629 | + return platform_driver_register(&max77686_rtc_driver); | |
| 630 | +} | |
| 631 | +module_init(max77686_rtc_init); | |
| 632 | + | |
| 633 | +static void __exit max77686_rtc_exit(void) | |
| 634 | +{ | |
| 635 | + platform_driver_unregister(&max77686_rtc_driver); | |
| 636 | +} | |
| 637 | +module_exit(max77686_rtc_exit); | |
| 638 | + | |
| 639 | +MODULE_DESCRIPTION("Maxim MAX77686 RTC driver"); | |
| 640 | +MODULE_AUTHOR("<woong.byun@samsung.com>"); | |
| 641 | +MODULE_LICENSE("GPL"); | |
| @@ -205,8 +205,9 @@ static int max8907_rtc_probe(struct platform_device *pdev) · 204 unmodified lines | ||
| 205 | 205 | goto err_unregister; |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | − ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler, | |
| 209 | − IRQF_ONESHOT, "max8907-alarm0", rtc); | |
| 208 | + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | |
| 209 | + max8907_irq_handler, | |
| 210 | + IRQF_ONESHOT, "max8907-alarm0", rtc); | |
| 210 | 211 | if (ret < 0) { |
| 211 | 212 | dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n", |
| 212 | 213 | rtc->irq, ret); |
| @@ -224,7 +225,6 @@ static int max8907_rtc_remove(struct platform_device *pdev) · 11 unmodified lines | ||
| 224 | 225 | { |
| 225 | 226 | struct max8907_rtc *rtc = platform_get_drvdata(pdev); |
| 226 | 227 | |
| 227 | − free_irq(rtc->irq, rtc); | |
| 228 | 228 | rtc_device_unregister(rtc->rtc_dev); |
| 229 | 229 | |
| 230 | 230 | return 0; |
| @@ -0,0 +1,552 @@ | ||
| 1 | +/* | |
| 2 | + * RTC driver for Maxim MAX8997 | |
| 3 | + * | |
| 4 | + * Copyright (C) 2013 Samsung Electronics Co.Ltd | |
| 5 | + * | |
| 6 | + * based on rtc-max8998.c | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + */ | |
| 14 | + | |
| 15 | +#include <linux/slab.h> | |
| 16 | +#include <linux/rtc.h> | |
| 17 | +#include <linux/delay.h> | |
| 18 | +#include <linux/mutex.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/platform_device.h> | |
| 21 | +#include <linux/mfd/max8997-private.h> | |
| 22 | +#include <linux/irqdomain.h> | |
| 23 | + | |
| 24 | +/* Module parameter for WTSR function control */ | |
| 25 | +static int wtsr_en = 1; | |
| 26 | +module_param(wtsr_en, int, 0444); | |
| 27 | +MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)"); | |
| 28 | +/* Module parameter for SMPL function control */ | |
| 29 | +static int smpl_en = 1; | |
| 30 | +module_param(smpl_en, int, 0444); | |
| 31 | +MODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)"); | |
| 32 | + | |
| 33 | +/* RTC Control Register */ | |
| 34 | +#define BCD_EN_SHIFT 0 | |
| 35 | +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) | |
| 36 | +#define MODEL24_SHIFT 1 | |
| 37 | +#define MODEL24_MASK (1 << MODEL24_SHIFT) | |
| 38 | +/* RTC Update Register1 */ | |
| 39 | +#define RTC_UDR_SHIFT 0 | |
| 40 | +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) | |
| 41 | +/* WTSR and SMPL Register */ | |
| 42 | +#define WTSRT_SHIFT 0 | |
| 43 | +#define SMPLT_SHIFT 2 | |
| 44 | +#define WTSR_EN_SHIFT 6 | |
| 45 | +#define SMPL_EN_SHIFT 7 | |
| 46 | +#define WTSRT_MASK (3 << WTSRT_SHIFT) | |
| 47 | +#define SMPLT_MASK (3 << SMPLT_SHIFT) | |
| 48 | +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) | |
| 49 | +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) | |
| 50 | +/* RTC Hour register */ | |
| 51 | +#define HOUR_PM_SHIFT 6 | |
| 52 | +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) | |
| 53 | +/* RTC Alarm Enable */ | |
| 54 | +#define ALARM_ENABLE_SHIFT 7 | |
| 55 | +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) | |
| 56 | + | |
| 57 | +enum { | |
| 58 | + RTC_SEC = 0, | |
| 59 | + RTC_MIN, | |
| 60 | + RTC_HOUR, | |
| 61 | + RTC_WEEKDAY, | |
| 62 | + RTC_MONTH, | |
| 63 | + RTC_YEAR, | |
| 64 | + RTC_DATE, | |
| 65 | + RTC_NR_TIME | |
| 66 | +}; | |
| 67 | + | |
| 68 | +struct max8997_rtc_info { | |
| 69 | + struct device *dev; | |
| 70 | + struct max8997_dev *max8997; | |
| 71 | + struct i2c_client *rtc; | |
| 72 | + struct rtc_device *rtc_dev; | |
| 73 | + struct mutex lock; | |
| 74 | + int virq; | |
| 75 | + int rtc_24hr_mode; | |
| 76 | +}; | |
| 77 | + | |
| 78 | +static void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm, | |
| 79 | + int rtc_24hr_mode) | |
| 80 | +{ | |
| 81 | + tm->tm_sec = data[RTC_SEC] & 0x7f; | |
| 82 | + tm->tm_min = data[RTC_MIN] & 0x7f; | |
| 83 | + if (rtc_24hr_mode) | |
| 84 | + tm->tm_hour = data[RTC_HOUR] & 0x1f; | |
| 85 | + else { | |
| 86 | + tm->tm_hour = data[RTC_HOUR] & 0x0f; | |
| 87 | + if (data[RTC_HOUR] & HOUR_PM_MASK) | |
| 88 | + tm->tm_hour += 12; | |
| 89 | + } | |
| 90 | + | |
| 91 | + tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1; | |
| 92 | + tm->tm_mday = data[RTC_DATE] & 0x1f; | |
| 93 | + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; | |
| 94 | + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; | |
| 95 | + tm->tm_yday = 0; | |
| 96 | + tm->tm_isdst = 0; | |
| 97 | +} | |
| 98 | + | |
| 99 | +static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data) | |
| 100 | +{ | |
| 101 | + data[RTC_SEC] = tm->tm_sec; | |
| 102 | + data[RTC_MIN] = tm->tm_min; | |
| 103 | + data[RTC_HOUR] = tm->tm_hour; | |
| 104 | + data[RTC_WEEKDAY] = 1 << tm->tm_wday; | |
| 105 | + data[RTC_DATE] = tm->tm_mday; | |
| 106 | + data[RTC_MONTH] = tm->tm_mon + 1; | |
| 107 | + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; | |
| 108 | + | |
| 109 | + if (tm->tm_year < 100) { | |
| 110 | + pr_warn("%s: MAX8997 RTC cannot handle the year %d." | |
| 111 | + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); | |
| 112 | + return -EINVAL; | |
| 113 | + } | |
| 114 | + return 0; | |
| 115 | +} | |
| 116 | + | |
| 117 | +static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info) | |
| 118 | +{ | |
| 119 | + int ret; | |
| 120 | + | |
| 121 | + ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1, | |
| 122 | + RTC_UDR_MASK); | |
| 123 | + if (ret < 0) | |
| 124 | + dev_err(info->dev, "%s: fail to write update reg(%d)\n", | |
| 125 | + __func__, ret); | |
| 126 | + else { | |
| 127 | + /* Minimum 16ms delay required before RTC update. | |
| 128 | + * Otherwise, we may read and update based on out-of-date | |
| 129 | + * value */ | |
| 130 | + msleep(20); | |
| 131 | + } | |
| 132 | + | |
| 133 | + return ret; | |
| 134 | +} | |
| 135 | + | |
| 136 | +static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
| 137 | +{ | |
| 138 | + struct max8997_rtc_info *info = dev_get_drvdata(dev); | |
| 139 | + u8 data[RTC_NR_TIME]; | |
| 140 | + int ret; | |
| 141 | + | |
| 142 | + mutex_lock(&info->lock); | |
| 143 | + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); | |
| 144 | + mutex_unlock(&info->lock); | |
| 145 | + | |
| 146 | + if (ret < 0) { | |
| 147 | + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, | |
| 148 | + ret); | |
| 149 | + return ret; | |
| 150 | + } | |
| 151 | + | |
| 152 | + max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); | |
| 153 | + | |
| 154 | + return rtc_valid_tm(tm); | |
| 155 | +} | |
| 156 | + | |
| 157 | +static int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
| 158 | +{ | |
| 159 | + struct max8997_rtc_info *info = dev_get_drvdata(dev); | |
| 160 | + u8 data[RTC_NR_TIME]; | |
| 161 | + int ret; | |
| 162 | + | |
| 163 | + ret = max8997_rtc_tm_to_data(tm, data); | |
| 164 | + if (ret < 0) | |
| 165 | + return ret; | |
| 166 | + | |
| 167 | + mutex_lock(&info->lock); | |
| 168 | + | |
| 169 | + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); | |
| 170 | + if (ret < 0) { | |
| 171 | + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, | |
| 172 | + ret); | |
| 173 | + goto out; | |
| 174 | + } | |
| 175 | + | |
| 176 | + ret = max8997_rtc_set_update_reg(info); | |
| 177 | +out: | |
| 178 | + mutex_unlock(&info->lock); | |
| 179 | + return ret; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 183 | +{ | |
| 184 | + struct max8997_rtc_info *info = dev_get_drvdata(dev); | |
| 185 | + u8 data[RTC_NR_TIME]; | |
| 186 | + u8 val; | |
| 187 | + int i, ret; | |
| 188 | + | |
| 189 | + mutex_lock(&info->lock); | |
| 190 | + | |
| 191 | + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 192 | + data); | |
| 193 | + if (ret < 0) { | |
| 194 | + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", | |
| 195 | + __func__, __LINE__, ret); | |
| 196 | + goto out; | |
| 197 | + } | |
| 198 | + | |
| 199 | + max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); | |
| 200 | + | |
| 201 | + alrm->enabled = 0; | |
| 202 | + for (i = 0; i < RTC_NR_TIME; i++) { | |
| 203 | + if (data[i] & ALARM_ENABLE_MASK) { | |
| 204 | + alrm->enabled = 1; | |
| 205 | + break; | |
| 206 | + } | |
| 207 | + } | |
| 208 | + | |
| 209 | + alrm->pending = 0; | |
| 210 | + ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val); | |
| 211 | + if (ret < 0) { | |
| 212 | + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", | |
| 213 | + __func__, __LINE__, ret); | |
| 214 | + goto out; | |
| 215 | + } | |
| 216 | + | |
| 217 | + if (val & (1 << 4)) /* RTCA1 */ | |
| 218 | + alrm->pending = 1; | |
| 219 | + | |
| 220 | +out: | |
| 221 | + mutex_unlock(&info->lock); | |
| 222 | + return 0; | |
| 223 | +} | |
| 224 | + | |
| 225 | +static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info) | |
| 226 | +{ | |
| 227 | + u8 data[RTC_NR_TIME]; | |
| 228 | + int ret, i; | |
| 229 | + | |
| 230 | + if (!mutex_is_locked(&info->lock)) | |
| 231 | + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
| 232 | + | |
| 233 | + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 234 | + data); | |
| 235 | + if (ret < 0) { | |
| 236 | + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", | |
| 237 | + __func__, ret); | |
| 238 | + goto out; | |
| 239 | + } | |
| 240 | + | |
| 241 | + for (i = 0; i < RTC_NR_TIME; i++) | |
| 242 | + data[i] &= ~ALARM_ENABLE_MASK; | |
| 243 | + | |
| 244 | + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 245 | + data); | |
| 246 | + if (ret < 0) { | |
| 247 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 248 | + __func__, ret); | |
| 249 | + goto out; | |
| 250 | + } | |
| 251 | + | |
| 252 | + ret = max8997_rtc_set_update_reg(info); | |
| 253 | +out: | |
| 254 | + return ret; | |
| 255 | +} | |
| 256 | + | |
| 257 | +static int max8997_rtc_start_alarm(struct max8997_rtc_info *info) | |
| 258 | +{ | |
| 259 | + u8 data[RTC_NR_TIME]; | |
| 260 | + int ret; | |
| 261 | + | |
| 262 | + if (!mutex_is_locked(&info->lock)) | |
| 263 | + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); | |
| 264 | + | |
| 265 | + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 266 | + data); | |
| 267 | + if (ret < 0) { | |
| 268 | + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", | |
| 269 | + __func__, ret); | |
| 270 | + goto out; | |
| 271 | + } | |
| 272 | + | |
| 273 | + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); | |
| 274 | + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); | |
| 275 | + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); | |
| 276 | + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; | |
| 277 | + if (data[RTC_MONTH] & 0xf) | |
| 278 | + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); | |
| 279 | + if (data[RTC_YEAR] & 0x7f) | |
| 280 | + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); | |
| 281 | + if (data[RTC_DATE] & 0x1f) | |
| 282 | + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); | |
| 283 | + | |
| 284 | + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 285 | + data); | |
| 286 | + if (ret < 0) { | |
| 287 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 288 | + __func__, ret); | |
| 289 | + goto out; | |
| 290 | + } | |
| 291 | + | |
| 292 | + ret = max8997_rtc_set_update_reg(info); | |
| 293 | +out: | |
| 294 | + return ret; | |
| 295 | +} | |
| 296 | +static int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 297 | +{ | |
| 298 | + struct max8997_rtc_info *info = dev_get_drvdata(dev); | |
| 299 | + u8 data[RTC_NR_TIME]; | |
| 300 | + int ret; | |
| 301 | + | |
| 302 | + ret = max8997_rtc_tm_to_data(&alrm->time, data); | |
| 303 | + if (ret < 0) | |
| 304 | + return ret; | |
| 305 | + | |
| 306 | + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__, | |
| 307 | + data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE], | |
| 308 | + data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]); | |
| 309 | + | |
| 310 | + mutex_lock(&info->lock); | |
| 311 | + | |
| 312 | + ret = max8997_rtc_stop_alarm(info); | |
| 313 | + if (ret < 0) | |
| 314 | + goto out; | |
| 315 | + | |
| 316 | + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, | |
| 317 | + data); | |
| 318 | + if (ret < 0) { | |
| 319 | + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", | |
| 320 | + __func__, ret); | |
| 321 | + goto out; | |
| 322 | + } | |
| 323 | + | |
| 324 | + ret = max8997_rtc_set_update_reg(info); | |
| 325 | + if (ret < 0) | |
| 326 | + goto out; | |
| 327 | + | |
| 328 | + if (alrm->enabled) | |
| 329 | + ret = max8997_rtc_start_alarm(info); | |
| 330 | +out: | |
| 331 | + mutex_unlock(&info->lock); | |
| 332 | + return ret; | |
| 333 | +} | |
| 334 | + | |
| 335 | +static int max8997_rtc_alarm_irq_enable(struct device *dev, | |
| 336 | + unsigned int enabled) | |
| 337 | +{ | |
| 338 | + struct max8997_rtc_info *info = dev_get_drvdata(dev); | |
| 339 | + int ret; | |
| 340 | + | |
| 341 | + mutex_lock(&info->lock); | |
| 342 | + if (enabled) | |
| 343 | + ret = max8997_rtc_start_alarm(info); | |
| 344 | + else | |
| 345 | + ret = max8997_rtc_stop_alarm(info); | |
| 346 | + mutex_unlock(&info->lock); | |
| 347 | + | |
| 348 | + return ret; | |
| 349 | +} | |
| 350 | + | |
| 351 | +static irqreturn_t max8997_rtc_alarm_irq(int irq, void *data) | |
| 352 | +{ | |
| 353 | + struct max8997_rtc_info *info = data; | |
| 354 | + | |
| 355 | + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); | |
| 356 | + | |
| 357 | + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); | |
| 358 | + | |
| 359 | + return IRQ_HANDLED; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static const struct rtc_class_ops max8997_rtc_ops = { | |
| 363 | + .read_time = max8997_rtc_read_time, | |
| 364 | + .set_time = max8997_rtc_set_time, | |
| 365 | + .read_alarm = max8997_rtc_read_alarm, | |
| 366 | + .set_alarm = max8997_rtc_set_alarm, | |
| 367 | + .alarm_irq_enable = max8997_rtc_alarm_irq_enable, | |
| 368 | +}; | |
| 369 | + | |
| 370 | +static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable) | |
| 371 | +{ | |
| 372 | + int ret; | |
| 373 | + u8 val, mask; | |
| 374 | + | |
| 375 | + if (!wtsr_en) | |
| 376 | + return; | |
| 377 | + | |
| 378 | + if (enable) | |
| 379 | + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); | |
| 380 | + else | |
| 381 | + val = 0; | |
| 382 | + | |
| 383 | + mask = WTSR_EN_MASK | WTSRT_MASK; | |
| 384 | + | |
| 385 | + dev_info(info->dev, "%s: %s WTSR\n", __func__, | |
| 386 | + enable ? "enable" : "disable"); | |
| 387 | + | |
| 388 | + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); | |
| 389 | + if (ret < 0) { | |
| 390 | + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", | |
| 391 | + __func__, ret); | |
| 392 | + return; | |
| 393 | + } | |
| 394 | + | |
| 395 | + max8997_rtc_set_update_reg(info); | |
| 396 | +} | |
| 397 | + | |
| 398 | +static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable) | |
| 399 | +{ | |
| 400 | + int ret; | |
| 401 | + u8 val, mask; | |
| 402 | + | |
| 403 | + if (!smpl_en) | |
| 404 | + return; | |
| 405 | + | |
| 406 | + if (enable) | |
| 407 | + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); | |
| 408 | + else | |
| 409 | + val = 0; | |
| 410 | + | |
| 411 | + mask = SMPL_EN_MASK | SMPLT_MASK; | |
| 412 | + | |
| 413 | + dev_info(info->dev, "%s: %s SMPL\n", __func__, | |
| 414 | + enable ? "enable" : "disable"); | |
| 415 | + | |
| 416 | + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); | |
| 417 | + if (ret < 0) { | |
| 418 | + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", | |
| 419 | + __func__, ret); | |
| 420 | + return; | |
| 421 | + } | |
| 422 | + | |
| 423 | + max8997_rtc_set_update_reg(info); | |
| 424 | + | |
| 425 | + val = 0; | |
| 426 | + max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val); | |
| 427 | + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); | |
| 428 | +} | |
| 429 | + | |
| 430 | +static int max8997_rtc_init_reg(struct max8997_rtc_info *info) | |
| 431 | +{ | |
| 432 | + u8 data[2]; | |
| 433 | + int ret; | |
| 434 | + | |
| 435 | + /* Set RTC control register : Binary mode, 24hour mdoe */ | |
| 436 | + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
| 437 | + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | |
| 438 | + | |
| 439 | + info->rtc_24hr_mode = 1; | |
| 440 | + | |
| 441 | + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data); | |
| 442 | + if (ret < 0) { | |
| 443 | + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", | |
| 444 | + __func__, ret); | |
| 445 | + return ret; | |
| 446 | + } | |
| 447 | + | |
| 448 | + ret = max8997_rtc_set_update_reg(info); | |
| 449 | + return ret; | |
| 450 | +} | |
| 451 | + | |
| 452 | +static int max8997_rtc_probe(struct platform_device *pdev) | |
| 453 | +{ | |
| 454 | + struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); | |
| 455 | + struct max8997_rtc_info *info; | |
| 456 | + int ret, virq; | |
| 457 | + | |
| 458 | + info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info), | |
| 459 | + GFP_KERNEL); | |
| 460 | + if (!info) | |
| 461 | + return -ENOMEM; | |
| 462 | + | |
| 463 | + mutex_init(&info->lock); | |
| 464 | + info->dev = &pdev->dev; | |
| 465 | + info->max8997 = max8997; | |
| 466 | + info->rtc = max8997->rtc; | |
| 467 | + | |
| 468 | + platform_set_drvdata(pdev, info); | |
| 469 | + | |
| 470 | + ret = max8997_rtc_init_reg(info); | |
| 471 | + | |
| 472 | + if (ret < 0) { | |
| 473 | + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); | |
| 474 | + return ret; | |
| 475 | + } | |
| 476 | + | |
| 477 | + max8997_rtc_enable_wtsr(info, true); | |
| 478 | + max8997_rtc_enable_smpl(info, true); | |
| 479 | + | |
| 480 | + device_init_wakeup(&pdev->dev, 1); | |
| 481 | + | |
| 482 | + info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev, | |
| 483 | + &max8997_rtc_ops, THIS_MODULE); | |
| 484 | + | |
| 485 | + if (IS_ERR(info->rtc_dev)) { | |
| 486 | + ret = PTR_ERR(info->rtc_dev); | |
| 487 | + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); | |
| 488 | + return ret; | |
| 489 | + } | |
| 490 | + | |
| 491 | + virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1); | |
| 492 | + if (!virq) { | |
| 493 | + dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n"); | |
| 494 | + goto err_out; | |
| 495 | + } | |
| 496 | + info->virq = virq; | |
| 497 | + | |
| 498 | + ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, | |
| 499 | + max8997_rtc_alarm_irq, 0, | |
| 500 | + "rtc-alarm0", info); | |
| 501 | + if (ret < 0) { | |
| 502 | + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", | |
| 503 | + info->virq, ret); | |
| 504 | + goto err_out; | |
| 505 | + } | |
| 506 | + | |
| 507 | + return ret; | |
| 508 | + | |
| 509 | +err_out: | |
| 510 | + rtc_device_unregister(info->rtc_dev); | |
| 511 | + return ret; | |
| 512 | +} | |
| 513 | + | |
| 514 | +static int max8997_rtc_remove(struct platform_device *pdev) | |
| 515 | +{ | |
| 516 | + struct max8997_rtc_info *info = platform_get_drvdata(pdev); | |
| 517 | + | |
| 518 | + if (info) | |
| 519 | + rtc_device_unregister(info->rtc_dev); | |
| 520 | + | |
| 521 | + return 0; | |
| 522 | +} | |
| 523 | + | |
| 524 | +static void max8997_rtc_shutdown(struct platform_device *pdev) | |
| 525 | +{ | |
| 526 | + struct max8997_rtc_info *info = platform_get_drvdata(pdev); | |
| 527 | + | |
| 528 | + max8997_rtc_enable_wtsr(info, false); | |
| 529 | + max8997_rtc_enable_smpl(info, false); | |
| 530 | +} | |
| 531 | + | |
| 532 | +static const struct platform_device_id rtc_id[] = { | |
| 533 | + { "max8997-rtc", 0 }, | |
| 534 | + {}, | |
| 535 | +}; | |
| 536 | + | |
| 537 | +static struct platform_driver max8997_rtc_driver = { | |
| 538 | + .driver = { | |
| 539 | + .name = "max8997-rtc", | |
| 540 | + .owner = THIS_MODULE, | |
| 541 | + }, | |
| 542 | + .probe = max8997_rtc_probe, | |
| 543 | + .remove = max8997_rtc_remove, | |
| 544 | + .shutdown = max8997_rtc_shutdown, | |
| 545 | + .id_table = rtc_id, | |
| 546 | +}; | |
| 547 | + | |
| 548 | +module_platform_driver(max8997_rtc_driver); | |
| 549 | + | |
| 550 | +MODULE_DESCRIPTION("Maxim MAX8997 RTC driver"); | |
| 551 | +MODULE_AUTHOR("<ms925.kim@samsung.com>"); | |
| 552 | +MODULE_LICENSE("GPL"); | |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/init.h> |
| 14 | 14 | #include <linux/module.h> |
| 15 | 15 | #include <linux/rtc.h> |
| 16 | +#include <linux/of.h> | |
| 16 | 17 | #include <linux/of_device.h> |
| 17 | 18 | #include <linux/of_platform.h> |
| 18 | 19 | #include <linux/io.h> |
| @@ -403,17 +404,19 @@ static int mpc5121_rtc_remove(struct platform_device *op) · 384 unmodified lines | ||
| 403 | 404 | return 0; |
| 404 | 405 | } |
| 405 | 406 | |
| 407 | +#ifdef CONFIG_OF | |
| 406 | 408 | static struct of_device_id mpc5121_rtc_match[] = { |
| 407 | 409 | { .compatible = "fsl,mpc5121-rtc", }, |
| 408 | 410 | { .compatible = "fsl,mpc5200-rtc", }, |
| 409 | 411 | {}, |
| 410 | 412 | }; |
| 413 | +#endif | |
| 411 | 414 | |
| 412 | 415 | static struct platform_driver mpc5121_rtc_driver = { |
| 413 | 416 | .driver = { |
| 414 | 417 | .name = "mpc5121-rtc", |
| 415 | 418 | .owner = THIS_MODULE, |
| 416 | − .of_match_table = mpc5121_rtc_match, | |
| 419 | + .of_match_table = of_match_ptr(mpc5121_rtc_match), | |
| 417 | 420 | }, |
| 418 | 421 | .probe = mpc5121_rtc_probe, |
| 419 | 422 | .remove = mpc5121_rtc_remove, |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ |
| 24 | 24 | #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ |
| 25 | 25 | #define REG_CONTROL3_PM_MASK 0xe0 |
| 26 | +#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */ | |
| 26 | 27 | |
| 27 | 28 | #define REG_SECONDS 0x03 |
| 28 | 29 | #define REG_SECONDS_OS (1 << 7) |
| @@ -250,9 +251,39 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) · 221 unmodified lines | ||
| 250 | 251 | return pcf8523_start_rtc(client); |
| 251 | 252 | } |
| 252 | 253 | |
| 254 | +#ifdef CONFIG_RTC_INTF_DEV | |
| 255 | +static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, | |
| 256 | + unsigned long arg) | |
| 257 | +{ | |
| 258 | + struct i2c_client *client = to_i2c_client(dev); | |
| 259 | + u8 value; | |
| 260 | + int ret = 0, err; | |
| 261 | + | |
| 262 | + switch (cmd) { | |
| 263 | + case RTC_VL_READ: | |
| 264 | + err = pcf8523_read(client, REG_CONTROL3, &value); | |
| 265 | + if (err < 0) | |
| 266 | + return err; | |
| 267 | + | |
| 268 | + if (value & REG_CONTROL3_BLF) | |
| 269 | + ret = 1; | |
| 270 | + | |
| 271 | + if (copy_to_user((void __user *)arg, &ret, sizeof(int))) | |
| 272 | + return -EFAULT; | |
| 273 | + | |
| 274 | + return 0; | |
| 275 | + default: | |
| 276 | + return -ENOIOCTLCMD; | |
| 277 | + } | |
| 278 | +} | |
| 279 | +#else | |
| 280 | +#define pcf8523_rtc_ioctl NULL | |
| 281 | +#endif | |
| 282 | + | |
| 253 | 283 | static const struct rtc_class_ops pcf8523_rtc_ops = { |
| 254 | 284 | .read_time = pcf8523_rtc_read_time, |
| 255 | 285 | .set_time = pcf8523_rtc_set_time, |
| 286 | + .ioctl = pcf8523_rtc_ioctl, | |
| 256 | 287 | }; |
| 257 | 288 | |
| 258 | 289 | static int pcf8523_probe(struct i2c_client *client, |
| @@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) · 180 unmodified lines | ||
| 181 | 181 | __func__, err, data[0], data[1]); |
| 182 | 182 | return -EIO; |
| 183 | 183 | } |
| 184 | − }; | |
| 184 | + } | |
| 185 | 185 | |
| 186 | 186 | return 0; |
| 187 | 187 | } |
| @@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) · 184 unmodified lines | ||
| 185 | 185 | if (ctrl & (CTRL_STOP | CTRL_HOLD)) { |
| 186 | 186 | unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD); |
| 187 | 187 | |
| 188 | − printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", | |
| 189 | − ctrl, new_ctrl); | |
| 188 | + dev_warn(dev, "resetting control %02x -> %02x\n", | |
| 189 | + ctrl, new_ctrl); | |
| 190 | 190 | |
| 191 | 191 | if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0) |
| 192 | 192 | return err; |
| @@ -384,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) · 383 unmodified lines | ||
| 384 | 384 | goto out_no_irq; |
| 385 | 385 | } |
| 386 | 386 | |
| 387 | + device_init_wakeup(&adev->dev, 1); | |
| 388 | + | |
| 387 | 389 | return 0; |
| 388 | 390 | |
| 389 | 391 | out_no_irq: |
| @@ -62,6 +62,10 @@ · 61 unmodified lines | ||
| 62 | 62 | #define RYxR_MONTH_S 5 |
| 63 | 63 | #define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S) |
| 64 | 64 | #define RYxR_DAY_MASK 0x1f |
| 65 | +#define RDxR_WOM_S 20 | |
| 66 | +#define RDxR_WOM_MASK (0x7 << RDxR_WOM_S) | |
| 67 | +#define RDxR_DOW_S 17 | |
| 68 | +#define RDxR_DOW_MASK (0x7 << RDxR_DOW_S) | |
| 65 | 69 | #define RDxR_HOUR_S 12 |
| 66 | 70 | #define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S) |
| 67 | 71 | #define RDxR_MIN_S 6 |
| @@ -91,6 +95,7 @@ struct pxa_rtc { · 23 unmodified lines | ||
| 91 | 95 | spinlock_t lock; /* Protects this structure */ |
| 92 | 96 | }; |
| 93 | 97 | |
| 98 | + | |
| 94 | 99 | static u32 ryxr_calc(struct rtc_time *tm) |
| 95 | 100 | { |
| 96 | 101 | return ((tm->tm_year + 1900) << RYxR_YEAR_S) |
| @@ -100,7 +105,10 @@ static u32 ryxr_calc(struct rtc_time *tm) · 3 unmodified lines | ||
| 100 | 105 | |
| 101 | 106 | static u32 rdxr_calc(struct rtc_time *tm) |
| 102 | 107 | { |
| 103 | − return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S) | |
| 108 | + return ((((tm->tm_mday + 6) / 7) << RDxR_WOM_S) & RDxR_WOM_MASK) | |
| 109 | + | (((tm->tm_wday + 1) << RDxR_DOW_S) & RDxR_DOW_MASK) | |
| 110 | + | (tm->tm_hour << RDxR_HOUR_S) | |
| 111 | + | (tm->tm_min << RDxR_MIN_S) | |
| 104 | 112 | | tm->tm_sec; |
| 105 | 113 | } |
| 106 | 114 | |
| @@ -109,6 +117,7 @@ static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm) · 2 unmodified lines | ||
| 109 | 117 | tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900; |
| 110 | 118 | tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1; |
| 111 | 119 | tm->tm_mday = (rycr & RYxR_DAY_MASK); |
| 120 | + tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1; | |
| 112 | 121 | tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S; |
| 113 | 122 | tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S; |
| 114 | 123 | tm->tm_sec = rdcr & RDxR_SEC_MASK; |
| @@ -300,8 +309,6 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) · 185 unmodified lines | ||
| 300 | 309 | } |
| 301 | 310 | |
| 302 | 311 | static const struct rtc_class_ops pxa_rtc_ops = { |
| 303 | − .open = pxa_rtc_open, | |
| 304 | − .release = pxa_rtc_release, | |
| 305 | 312 | .read_time = pxa_rtc_read_time, |
| 306 | 313 | .set_time = pxa_rtc_set_time, |
| 307 | 314 | .read_alarm = pxa_rtc_read_alarm, |
| @@ -341,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) · 33 unmodified lines | ||
| 341 | 348 | dev_err(dev, "No alarm IRQ resource defined\n"); |
| 342 | 349 | goto err_ress; |
| 343 | 350 | } |
| 344 | − | |
| 351 | + pxa_rtc_open(dev); | |
| 345 | 352 | ret = -ENOMEM; |
| 346 | 353 | pxa_rtc->base = ioremap(pxa_rtc->ress->start, |
| 347 | 354 | resource_size(pxa_rtc->ress)); |
| @@ -387,6 +394,9 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) · 39 unmodified lines | ||
| 387 | 394 | { |
| 388 | 395 | struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); |
| 389 | 396 | |
| 397 | + struct device *dev = &pdev->dev; | |
| 398 | + pxa_rtc_release(dev); | |
| 399 | + | |
| 390 | 400 | rtc_device_unregister(pxa_rtc->rtc); |
| 391 | 401 | |
| 392 | 402 | spin_lock_irq(&pxa_rtc->lock); |
| @@ -444,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = { · 51 unmodified lines | ||
| 444 | 454 | |
| 445 | 455 | static int __init pxa_rtc_init(void) |
| 446 | 456 | { |
| 447 | − if (cpu_is_pxa27x() || cpu_is_pxa3xx()) | |
| 448 | − return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); | |
| 449 | − | |
| 450 | − return -ENODEV; | |
| 457 | + return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); | |
| 451 | 458 | } |
| 452 | 459 | |
| 453 | 460 | static void __exit pxa_rtc_exit(void) |
| @@ -39,6 +39,8 @@ · 38 unmodified lines | ||
| 39 | 39 | * 1.13 Nobuhiro Iwamatsu: Updata driver. |
| 40 | 40 | */ |
| 41 | 41 | |
| 42 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 43 | + | |
| 42 | 44 | #include <linux/module.h> |
| 43 | 45 | #include <linux/err.h> |
| 44 | 46 | #include <linux/rtc.h> |
| @@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void) · 307 unmodified lines | ||
| 352 | 354 | tm.tm_year = 2000 - 1900; |
| 353 | 355 | |
| 354 | 356 | rs5c313_rtc_set_time(NULL, &tm); |
| 355 | − printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " | |
| 356 | − "1 Jan 2000\n"); | |
| 357 | + pr_err("invalid value, resetting to 1 Jan 2000\n"); | |
| 357 | 358 | } |
| 358 | 359 | RS5C313_CEDISABLE; |
| 359 | 360 | ndelay(700); /* CE:L */ |
| @@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) · 310 unmodified lines | ||
| 311 | 311 | buf &= ~RS5C_CTRL1_AALE; |
| 312 | 312 | |
| 313 | 313 | if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { |
| 314 | − printk(KERN_WARNING "%s: can't update alarm\n", | |
| 315 | − rs5c->rtc->name); | |
| 314 | + dev_warn(dev, "can't update alarm\n"); | |
| 316 | 315 | status = -EIO; |
| 317 | 316 | } else |
| 318 | 317 | rs5c->regs[RS5C_REG_CTRL1] = buf; |
| @@ -381,7 +380,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) · 62 unmodified lines | ||
| 381 | 380 | addr = RS5C_ADDR(RS5C_REG_CTRL1); |
| 382 | 381 | buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; |
| 383 | 382 | if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) { |
| 384 | − pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); | |
| 383 | + dev_dbg(dev, "can't disable alarm\n"); | |
| 385 | 384 | return -EIO; |
| 386 | 385 | } |
| 387 | 386 | rs5c->regs[RS5C_REG_CTRL1] = buf[0]; |
| @@ -395,7 +394,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) · 7 unmodified lines | ||
| 395 | 394 | for (i = 0; i < sizeof(buf); i++) { |
| 396 | 395 | addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); |
| 397 | 396 | if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) { |
| 398 | − pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); | |
| 397 | + dev_dbg(dev, "can't set alarm time\n"); | |
| 399 | 398 | return -EIO; |
| 400 | 399 | } |
| 401 | 400 | } |
| @@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) · 3 unmodified lines | ||
| 405 | 404 | addr = RS5C_ADDR(RS5C_REG_CTRL1); |
| 406 | 405 | buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; |
| 407 | 406 | if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) |
| 408 | − printk(KERN_WARNING "%s: can't enable alarm\n", | |
| 409 | − rs5c->rtc->name); | |
| 407 | + dev_warn(dev, "can't enable alarm\n"); | |
| 410 | 408 | rs5c->regs[RS5C_REG_CTRL1] = buf[0]; |
| 411 | 409 | } |
| 412 | 410 | |
| @@ -0,0 +1,314 @@ | ||
| 1 | +/* drivers/rtc/rtc-rx4581.c | |
| 2 | + * | |
| 3 | + * written by Torben Hohn <torbenh@linutronix.de> | |
| 4 | + * | |
| 5 | + * Based on: | |
| 6 | + * drivers/rtc/rtc-max6902.c | |
| 7 | + * | |
| 8 | + * Copyright (C) 2006 8D Technologies inc. | |
| 9 | + * Copyright (C) 2004 Compulab Ltd. | |
| 10 | + * | |
| 11 | + * This program is free software; you can redistribute it and/or modify | |
| 12 | + * it under the terms of the GNU General Public License version 2 as | |
| 13 | + * published by the Free Software Foundation. | |
| 14 | + * | |
| 15 | + * Driver for MAX6902 spi RTC | |
| 16 | + * | |
| 17 | + * and based on: | |
| 18 | + * drivers/rtc/rtc-rx8581.c | |
| 19 | + * | |
| 20 | + * An I2C driver for the Epson RX8581 RTC | |
| 21 | + * | |
| 22 | + * Author: Martyn Welch <martyn.welch@ge.com> | |
| 23 | + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. | |
| 24 | + * | |
| 25 | + * This program is free software; you can redistribute it and/or modify | |
| 26 | + * it under the terms of the GNU General Public License version 2 as | |
| 27 | + * published by the Free Software Foundation. | |
| 28 | + * | |
| 29 | + * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) | |
| 30 | + * Copyright 2005-06 Tower Technologies | |
| 31 | + * | |
| 32 | + */ | |
| 33 | + | |
| 34 | +#include <linux/module.h> | |
| 35 | +#include <linux/kernel.h> | |
| 36 | +#include <linux/platform_device.h> | |
| 37 | +#include <linux/init.h> | |
| 38 | +#include <linux/rtc.h> | |
| 39 | +#include <linux/spi/spi.h> | |
| 40 | +#include <linux/bcd.h> | |
| 41 | + | |
| 42 | +#define RX4581_REG_SC 0x00 /* Second in BCD */ | |
| 43 | +#define RX4581_REG_MN 0x01 /* Minute in BCD */ | |
| 44 | +#define RX4581_REG_HR 0x02 /* Hour in BCD */ | |
| 45 | +#define RX4581_REG_DW 0x03 /* Day of Week */ | |
| 46 | +#define RX4581_REG_DM 0x04 /* Day of Month in BCD */ | |
| 47 | +#define RX4581_REG_MO 0x05 /* Month in BCD */ | |
| 48 | +#define RX4581_REG_YR 0x06 /* Year in BCD */ | |
| 49 | +#define RX4581_REG_RAM 0x07 /* RAM */ | |
| 50 | +#define RX4581_REG_AMN 0x08 /* Alarm Min in BCD*/ | |
| 51 | +#define RX4581_REG_AHR 0x09 /* Alarm Hour in BCD */ | |
| 52 | +#define RX4581_REG_ADM 0x0A | |
| 53 | +#define RX4581_REG_ADW 0x0A | |
| 54 | +#define RX4581_REG_TMR0 0x0B | |
| 55 | +#define RX4581_REG_TMR1 0x0C | |
| 56 | +#define RX4581_REG_EXT 0x0D /* Extension Register */ | |
| 57 | +#define RX4581_REG_FLAG 0x0E /* Flag Register */ | |
| 58 | +#define RX4581_REG_CTRL 0x0F /* Control Register */ | |
| 59 | + | |
| 60 | + | |
| 61 | +/* Flag Register bit definitions */ | |
| 62 | +#define RX4581_FLAG_UF 0x20 /* Update */ | |
| 63 | +#define RX4581_FLAG_TF 0x10 /* Timer */ | |
| 64 | +#define RX4581_FLAG_AF 0x08 /* Alarm */ | |
| 65 | +#define RX4581_FLAG_VLF 0x02 /* Voltage Low */ | |
| 66 | + | |
| 67 | +/* Control Register bit definitions */ | |
| 68 | +#define RX4581_CTRL_UIE 0x20 /* Update Interrupt Enable */ | |
| 69 | +#define RX4581_CTRL_TIE 0x10 /* Timer Interrupt Enable */ | |
| 70 | +#define RX4581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */ | |
| 71 | +#define RX4581_CTRL_STOP 0x02 /* STOP bit */ | |
| 72 | +#define RX4581_CTRL_RESET 0x01 /* RESET bit */ | |
| 73 | + | |
| 74 | +static int rx4581_set_reg(struct device *dev, unsigned char address, | |
| 75 | + unsigned char data) | |
| 76 | +{ | |
| 77 | + struct spi_device *spi = to_spi_device(dev); | |
| 78 | + unsigned char buf[2]; | |
| 79 | + | |
| 80 | + /* high nibble must be '0' to write */ | |
| 81 | + buf[0] = address & 0x0f; | |
| 82 | + buf[1] = data; | |
| 83 | + | |
| 84 | + return spi_write_then_read(spi, buf, 2, NULL, 0); | |
| 85 | +} | |
| 86 | + | |
| 87 | +static int rx4581_get_reg(struct device *dev, unsigned char address, | |
| 88 | + unsigned char *data) | |
| 89 | +{ | |
| 90 | + struct spi_device *spi = to_spi_device(dev); | |
| 91 | + | |
| 92 | + /* Set MSB to indicate read */ | |
| 93 | + *data = address | 0x80; | |
| 94 | + | |
| 95 | + return spi_write_then_read(spi, data, 1, data, 1); | |
| 96 | +} | |
| 97 | + | |
| 98 | +/* | |
| 99 | + * In the routines that deal directly with the rx8581 hardware, we use | |
| 100 | + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | |
| 101 | + */ | |
| 102 | +static int rx4581_get_datetime(struct device *dev, struct rtc_time *tm) | |
| 103 | +{ | |
| 104 | + struct spi_device *spi = to_spi_device(dev); | |
| 105 | + unsigned char date[7]; | |
| 106 | + unsigned char data; | |
| 107 | + int err; | |
| 108 | + | |
| 109 | + /* First we ensure that the "update flag" is not set, we read the | |
| 110 | + * time and date then re-read the "update flag". If the update flag | |
| 111 | + * has been set, we know that the time has changed during the read so | |
| 112 | + * we repeat the whole process again. | |
| 113 | + */ | |
| 114 | + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); | |
| 115 | + if (err != 0) { | |
| 116 | + dev_err(dev, "Unable to read device flags\n"); | |
| 117 | + return -EIO; | |
| 118 | + } | |
| 119 | + | |
| 120 | + do { | |
| 121 | + /* If update flag set, clear it */ | |
| 122 | + if (data & RX4581_FLAG_UF) { | |
| 123 | + err = rx4581_set_reg(dev, | |
| 124 | + RX4581_REG_FLAG, (data & ~RX4581_FLAG_UF)); | |
| 125 | + if (err != 0) { | |
| 126 | + dev_err(dev, "Unable to write device " | |
| 127 | + "flags\n"); | |
| 128 | + return -EIO; | |
| 129 | + } | |
| 130 | + } | |
| 131 | + | |
| 132 | + /* Now read time and date */ | |
| 133 | + date[0] = 0x80; | |
| 134 | + err = spi_write_then_read(spi, date, 1, date, 7); | |
| 135 | + if (err < 0) { | |
| 136 | + dev_err(dev, "Unable to read date\n"); | |
| 137 | + return -EIO; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /* Check flag register */ | |
| 141 | + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); | |
| 142 | + if (err != 0) { | |
| 143 | + dev_err(dev, "Unable to read device flags\n"); | |
| 144 | + return -EIO; | |
| 145 | + } | |
| 146 | + } while (data & RX4581_FLAG_UF); | |
| 147 | + | |
| 148 | + if (data & RX4581_FLAG_VLF) | |
| 149 | + dev_info(dev, | |
| 150 | + "low voltage detected, date/time is not reliable.\n"); | |
| 151 | + | |
| 152 | + dev_dbg(dev, | |
| 153 | + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " | |
| 154 | + "wday=%02x, mday=%02x, mon=%02x, year=%02x\n", | |
| 155 | + __func__, | |
| 156 | + date[0], date[1], date[2], date[3], date[4], date[5], date[6]); | |
| 157 | + | |
| 158 | + tm->tm_sec = bcd2bin(date[RX4581_REG_SC] & 0x7F); | |
| 159 | + tm->tm_min = bcd2bin(date[RX4581_REG_MN] & 0x7F); | |
| 160 | + tm->tm_hour = bcd2bin(date[RX4581_REG_HR] & 0x3F); /* rtc hr 0-23 */ | |
| 161 | + tm->tm_wday = ilog2(date[RX4581_REG_DW] & 0x7F); | |
| 162 | + tm->tm_mday = bcd2bin(date[RX4581_REG_DM] & 0x3F); | |
| 163 | + tm->tm_mon = bcd2bin(date[RX4581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ | |
| 164 | + tm->tm_year = bcd2bin(date[RX4581_REG_YR]); | |
| 165 | + if (tm->tm_year < 70) | |
| 166 | + tm->tm_year += 100; /* assume we are in 1970...2069 */ | |
| 167 | + | |
| 168 | + | |
| 169 | + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | |
| 170 | + "mday=%d, mon=%d, year=%d, wday=%d\n", | |
| 171 | + __func__, | |
| 172 | + tm->tm_sec, tm->tm_min, tm->tm_hour, | |
| 173 | + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | |
| 174 | + | |
| 175 | + err = rtc_valid_tm(tm); | |
| 176 | + if (err < 0) | |
| 177 | + dev_err(dev, "retrieved date/time is not valid.\n"); | |
| 178 | + | |
| 179 | + return err; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int rx4581_set_datetime(struct device *dev, struct rtc_time *tm) | |
| 183 | +{ | |
| 184 | + struct spi_device *spi = to_spi_device(dev); | |
| 185 | + int err; | |
| 186 | + unsigned char buf[8], data; | |
| 187 | + | |
| 188 | + dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, " | |
| 189 | + "mday=%d, mon=%d, year=%d, wday=%d\n", | |
| 190 | + __func__, | |
| 191 | + tm->tm_sec, tm->tm_min, tm->tm_hour, | |
| 192 | + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | |
| 193 | + | |
| 194 | + buf[0] = 0x00; | |
| 195 | + /* hours, minutes and seconds */ | |
| 196 | + buf[RX4581_REG_SC+1] = bin2bcd(tm->tm_sec); | |
| 197 | + buf[RX4581_REG_MN+1] = bin2bcd(tm->tm_min); | |
| 198 | + buf[RX4581_REG_HR+1] = bin2bcd(tm->tm_hour); | |
| 199 | + | |
| 200 | + buf[RX4581_REG_DM+1] = bin2bcd(tm->tm_mday); | |
| 201 | + | |
| 202 | + /* month, 1 - 12 */ | |
| 203 | + buf[RX4581_REG_MO+1] = bin2bcd(tm->tm_mon + 1); | |
| 204 | + | |
| 205 | + /* year and century */ | |
| 206 | + buf[RX4581_REG_YR+1] = bin2bcd(tm->tm_year % 100); | |
| 207 | + buf[RX4581_REG_DW+1] = (0x1 << tm->tm_wday); | |
| 208 | + | |
| 209 | + /* Stop the clock */ | |
| 210 | + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); | |
| 211 | + if (err != 0) { | |
| 212 | + dev_err(dev, "Unable to read control register\n"); | |
| 213 | + return -EIO; | |
| 214 | + } | |
| 215 | + | |
| 216 | + err = rx4581_set_reg(dev, RX4581_REG_CTRL, | |
| 217 | + (data | RX4581_CTRL_STOP)); | |
| 218 | + if (err != 0) { | |
| 219 | + dev_err(dev, "Unable to write control register\n"); | |
| 220 | + return -EIO; | |
| 221 | + } | |
| 222 | + | |
| 223 | + /* write register's data */ | |
| 224 | + err = spi_write_then_read(spi, buf, 8, NULL, 0); | |
| 225 | + if (err != 0) { | |
| 226 | + dev_err(dev, "Unable to write to date registers\n"); | |
| 227 | + return -EIO; | |
| 228 | + } | |
| 229 | + | |
| 230 | + /* get VLF and clear it */ | |
| 231 | + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); | |
| 232 | + if (err != 0) { | |
| 233 | + dev_err(dev, "Unable to read flag register\n"); | |
| 234 | + return -EIO; | |
| 235 | + } | |
| 236 | + | |
| 237 | + err = rx4581_set_reg(dev, RX4581_REG_FLAG, | |
| 238 | + (data & ~(RX4581_FLAG_VLF))); | |
| 239 | + if (err != 0) { | |
| 240 | + dev_err(dev, "Unable to write flag register\n"); | |
| 241 | + return -EIO; | |
| 242 | + } | |
| 243 | + | |
| 244 | + /* Restart the clock */ | |
| 245 | + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); | |
| 246 | + if (err != 0) { | |
| 247 | + dev_err(dev, "Unable to read control register\n"); | |
| 248 | + return -EIO; | |
| 249 | + } | |
| 250 | + | |
| 251 | + err = rx4581_set_reg(dev, RX4581_REG_CTRL, | |
| 252 | + (data & ~(RX4581_CTRL_STOP))); | |
| 253 | + if (err != 0) { | |
| 254 | + dev_err(dev, "Unable to write control register\n"); | |
| 255 | + return -EIO; | |
| 256 | + } | |
| 257 | + | |
| 258 | + return 0; | |
| 259 | +} | |
| 260 | + | |
| 261 | +static const struct rtc_class_ops rx4581_rtc_ops = { | |
| 262 | + .read_time = rx4581_get_datetime, | |
| 263 | + .set_time = rx4581_set_datetime, | |
| 264 | +}; | |
| 265 | + | |
| 266 | +static int rx4581_probe(struct spi_device *spi) | |
| 267 | +{ | |
| 268 | + struct rtc_device *rtc; | |
| 269 | + unsigned char tmp; | |
| 270 | + int res; | |
| 271 | + | |
| 272 | + res = rx4581_get_reg(&spi->dev, RX4581_REG_SC, &tmp); | |
| 273 | + if (res != 0) | |
| 274 | + return res; | |
| 275 | + | |
| 276 | + rtc = rtc_device_register("rx4581", | |
| 277 | + &spi->dev, &rx4581_rtc_ops, THIS_MODULE); | |
| 278 | + if (IS_ERR(rtc)) | |
| 279 | + return PTR_ERR(rtc); | |
| 280 | + | |
| 281 | + dev_set_drvdata(&spi->dev, rtc); | |
| 282 | + return 0; | |
| 283 | +} | |
| 284 | + | |
| 285 | +static int rx4581_remove(struct spi_device *spi) | |
| 286 | +{ | |
| 287 | + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); | |
| 288 | + | |
| 289 | + rtc_device_unregister(rtc); | |
| 290 | + return 0; | |
| 291 | +} | |
| 292 | + | |
| 293 | +static const struct spi_device_id rx4581_id[] = { | |
| 294 | + { "rx4581", 0 }, | |
| 295 | + { } | |
| 296 | +}; | |
| 297 | +MODULE_DEVICE_TABLE(spi, rx4581_id); | |
| 298 | + | |
| 299 | +static struct spi_driver rx4581_driver = { | |
| 300 | + .driver = { | |
| 301 | + .name = "rtc-rx4581", | |
| 302 | + .owner = THIS_MODULE, | |
| 303 | + }, | |
| 304 | + .probe = rx4581_probe, | |
| 305 | + .remove = rx4581_remove, | |
| 306 | + .id_table = rx4581_id, | |
| 307 | +}; | |
| 308 | + | |
| 309 | +module_spi_driver(rx4581_driver); | |
| 310 | + | |
| 311 | +MODULE_DESCRIPTION("rx4581 spi RTC driver"); | |
| 312 | +MODULE_AUTHOR("Torben Hohn"); | |
| 313 | +MODULE_LICENSE("GPL"); | |
| 314 | +MODULE_ALIAS("spi:rtc-rx4581"); | |
| @@ -115,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) · 114 unmodified lines | ||
| 115 | 115 | { |
| 116 | 116 | unsigned int tmp; |
| 117 | 117 | |
| 118 | − pr_debug("%s: aie=%d\n", __func__, enabled); | |
| 118 | + dev_dbg(dev, "%s: aie=%d\n", __func__, enabled); | |
| 119 | 119 | |
| 120 | 120 | clk_enable(rtc_clk); |
| 121 | 121 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; |
| @@ -203,7 +203,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) · 81 unmodified lines | ||
| 203 | 203 | |
| 204 | 204 | rtc_tm->tm_year += 100; |
| 205 | 205 | |
| 206 | − pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 206 | + dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 207 | 207 | 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, |
| 208 | 208 | rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); |
| 209 | 209 | |
| @@ -218,7 +218,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) · 8 unmodified lines | ||
| 218 | 218 | void __iomem *base = s3c_rtc_base; |
| 219 | 219 | int year = tm->tm_year - 100; |
| 220 | 220 | |
| 221 | − pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 221 | + dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 222 | 222 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
| 223 | 223 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
| 224 | 224 | |
| @@ -259,7 +259,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) · 34 unmodified lines | ||
| 259 | 259 | |
| 260 | 260 | alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; |
| 261 | 261 | |
| 262 | − pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 262 | + dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 263 | 263 | alm_en, |
| 264 | 264 | 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, |
| 265 | 265 | alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); |
| @@ -310,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) · 44 unmodified lines | ||
| 310 | 310 | unsigned int alrm_en; |
| 311 | 311 | |
| 312 | 312 | clk_enable(rtc_clk); |
| 313 | − pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 313 | + dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", | |
| 314 | 314 | alrm->enabled, |
| 315 | 315 | 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, |
| 316 | 316 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
| @@ -333,7 +333,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) · 16 unmodified lines | ||
| 333 | 333 | writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR); |
| 334 | 334 | } |
| 335 | 335 | |
| 336 | − pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); | |
| 336 | + dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); | |
| 337 | 337 | |
| 338 | 338 | writeb(alrm_en, base + S3C2410_RTCALM); |
| 339 | 339 | |
| @@ -459,7 +459,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) · 119 unmodified lines | ||
| 459 | 459 | int ret; |
| 460 | 460 | int tmp; |
| 461 | 461 | |
| 462 | − pr_debug("%s: probe=%p\n", __func__, pdev); | |
| 462 | + dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev); | |
| 463 | 463 | |
| 464 | 464 | /* find the IRQs */ |
| 465 | 465 | |
| @@ -475,7 +475,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 475 | 475 | return s3c_rtc_alarmno; |
| 476 | 476 | } |
| 477 | 477 | |
| 478 | − pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", | |
| 478 | + dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", | |
| 479 | 479 | s3c_rtc_tickno, s3c_rtc_alarmno); |
| 480 | 480 | |
| 481 | 481 | /* get the memory region */ |
| @@ -504,7 +504,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) · 22 unmodified lines | ||
| 504 | 504 | |
| 505 | 505 | s3c_rtc_enable(pdev, 1); |
| 506 | 506 | |
| 507 | − pr_debug("s3c2410_rtc: RTCCON=%02x\n", | |
| 507 | + dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", | |
| 508 | 508 | readw(s3c_rtc_base + S3C2410_RTCCON)); |
| 509 | 509 | |
| 510 | 510 | device_init_wakeup(&pdev->dev, 1); |
| @@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev) · 107 unmodified lines | ||
| 108 | 108 | struct rtc_device *rtc = info->rtc; |
| 109 | 109 | int ret; |
| 110 | 110 | |
| 111 | − ret = clk_prepare_enable(info->clk); | |
| 112 | − if (ret) | |
| 113 | − goto fail_clk; | |
| 114 | 111 | ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); |
| 115 | 112 | if (ret) { |
| 116 | 113 | dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); |
| @@ -130,7 +127,6 @@ static int sa1100_rtc_open(struct device *dev) · 13 unmodified lines | ||
| 130 | 127 | free_irq(info->irq_1hz, dev); |
| 131 | 128 | fail_ui: |
| 132 | 129 | clk_disable_unprepare(info->clk); |
| 133 | − fail_clk: | |
| 134 | 130 | return ret; |
| 135 | 131 | } |
| 136 | 132 | |
| @@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev) · 7 unmodified lines | ||
| 144 | 140 | |
| 145 | 141 | free_irq(info->irq_alarm, dev); |
| 146 | 142 | free_irq(info->irq_1hz, dev); |
| 147 | − clk_disable_unprepare(info->clk); | |
| 148 | 143 | } |
| 149 | 144 | |
| 150 | 145 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
| @@ -253,6 +248,9 @@ static int sa1100_rtc_probe(struct platform_device *pdev) · 102 unmodified lines | ||
| 253 | 248 | spin_lock_init(&info->lock); |
| 254 | 249 | platform_set_drvdata(pdev, info); |
| 255 | 250 | |
| 251 | + ret = clk_prepare_enable(info->clk); | |
| 252 | + if (ret) | |
| 253 | + goto err_enable_clk; | |
| 256 | 254 | /* |
| 257 | 255 | * According to the manual we should be able to let RTTR be zero |
| 258 | 256 | * and then a default diviser for a 32.768KHz clock is used. |
| @@ -305,6 +303,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) · 46 unmodified lines | ||
| 305 | 303 | |
| 306 | 304 | return 0; |
| 307 | 305 | err_dev: |
| 306 | + clk_disable_unprepare(info->clk); | |
| 307 | +err_enable_clk: | |
| 308 | 308 | platform_set_drvdata(pdev, NULL); |
| 309 | 309 | clk_put(info->clk); |
| 310 | 310 | err_clk: |
| @@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 318 | 318 | |
| 319 | 319 | if (info) { |
| 320 | 320 | rtc_device_unregister(info->rtc); |
| 321 | + clk_disable_unprepare(info->clk); | |
| 321 | 322 | clk_put(info->clk); |
| 322 | 323 | platform_set_drvdata(pdev, NULL); |
| 323 | 324 | kfree(info); |
| @@ -349,12 +350,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { · 25 unmodified lines | ||
| 349 | 350 | }; |
| 350 | 351 | #endif |
| 351 | 352 | |
| 353 | +#ifdef CONFIG_OF | |
| 352 | 354 | static struct of_device_id sa1100_rtc_dt_ids[] = { |
| 353 | 355 | { .compatible = "mrvl,sa1100-rtc", }, |
| 354 | 356 | { .compatible = "mrvl,mmp-rtc", }, |
| 355 | 357 | {} |
| 356 | 358 | }; |
| 357 | 359 | MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); |
| 360 | +#endif | |
| 358 | 361 | |
| 359 | 362 | static struct platform_driver sa1100_rtc_driver = { |
| 360 | 363 | .probe = sa1100_rtc_probe, |
| @@ -364,7 +367,7 @@ static struct platform_driver sa1100_rtc_driver = { · 3 unmodified lines | ||
| 364 | 367 | #ifdef CONFIG_PM |
| 365 | 368 | .pm = &sa1100_rtc_pm_ops, |
| 366 | 369 | #endif |
| 367 | − .of_match_table = sa1100_rtc_dt_ids, | |
| 370 | + .of_match_table = of_match_ptr(sa1100_rtc_dt_ids), | |
| 368 | 371 | }, |
| 369 | 372 | }; |
| 370 | 373 | |
| @@ -338,7 +338,7 @@ static struct platform_driver snvs_rtc_driver = { · 337 unmodified lines | ||
| 338 | 338 | .name = "snvs_rtc", |
| 339 | 339 | .owner = THIS_MODULE, |
| 340 | 340 | .pm = &snvs_rtc_pm_ops, |
| 341 | − .of_match_table = snvs_dt_ids, | |
| 341 | + .of_match_table = of_match_ptr(snvs_dt_ids), | |
| 342 | 342 | }, |
| 343 | 343 | .probe = snvs_rtc_probe, |
| 344 | 344 | .remove = snvs_rtc_remove, |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/rtc.h> |
| 27 | 27 | #include <linux/slab.h> |
| 28 | 28 | #include <linux/of_device.h> |
| 29 | +#include <linux/of.h> | |
| 29 | 30 | |
| 30 | 31 | #include <mach/common.h> |
| 31 | 32 | |
| @@ -280,7 +281,7 @@ static struct platform_driver stmp3xxx_rtcdrv = { · 248 unmodified lines | ||
| 280 | 281 | .driver = { |
| 281 | 282 | .name = "stmp3xxx-rtc", |
| 282 | 283 | .owner = THIS_MODULE, |
| 283 | − .of_match_table = rtc_dt_ids, | |
| 284 | + .of_match_table = of_match_ptr(rtc_dt_ids), | |
| 284 | 285 | }, |
| 285 | 286 | }; |
| 286 | 287 | |
| @@ -3,6 +3,8 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> |
| 4 | 4 | */ |
| 5 | 5 | |
| 6 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 7 | + | |
| 6 | 8 | #include <linux/kernel.h> |
| 7 | 9 | #include <linux/module.h> |
| 8 | 10 | #include <linux/delay.h> |
| @@ -26,10 +28,10 @@ retry: · 17 unmodified lines | ||
| 26 | 28 | udelay(100); |
| 27 | 29 | goto retry; |
| 28 | 30 | } |
| 29 | − printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); | |
| 31 | + pr_warn("tod_get() timed out.\n"); | |
| 30 | 32 | return 0; |
| 31 | 33 | } |
| 32 | − printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); | |
| 34 | + pr_warn("tod_get() not supported.\n"); | |
| 33 | 35 | return 0; |
| 34 | 36 | } |
| 35 | 37 | |
| @@ -53,10 +55,10 @@ retry: · 17 unmodified lines | ||
| 53 | 55 | udelay(100); |
| 54 | 56 | goto retry; |
| 55 | 57 | } |
| 56 | − printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); | |
| 58 | + pr_warn("tod_set() timed out.\n"); | |
| 57 | 59 | return -EAGAIN; |
| 58 | 60 | } |
| 59 | − printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); | |
| 61 | + pr_warn("tod_set() not supported.\n"); | |
| 60 | 62 | return -EOPNOTSUPP; |
| 61 | 63 | } |
| 62 | 64 | |
| @@ -282,7 +282,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) · 281 unmodified lines | ||
| 282 | 282 | goto fail_rtc_register; |
| 283 | 283 | } |
| 284 | 284 | |
| 285 | − ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq, | |
| 285 | + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | |
| 286 | + tps6586x_rtc_irq, | |
| 286 | 287 | IRQF_ONESHOT | IRQF_EARLY_RESUME, |
| 287 | 288 | dev_name(&pdev->dev), rtc); |
| 288 | 289 | if (ret < 0) { |
| @@ -311,7 +312,6 @@ static int tps6586x_rtc_remove(struct platform_device *pdev) · 22 unmodified lines | ||
| 311 | 312 | tps6586x_update(tps_dev, RTC_CTRL, 0, |
| 312 | 313 | RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); |
| 313 | 314 | rtc_device_unregister(rtc->rtc); |
| 314 | − free_irq(rtc->irq, rtc); | |
| 315 | 315 | return 0; |
| 316 | 316 | } |
| 317 | 317 | |
| @@ -22,13 +22,13 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/rtc.h> |
| 23 | 23 | #include <linux/bcd.h> |
| 24 | 24 | #include <linux/platform_device.h> |
| 25 | +#include <linux/pm_runtime.h> | |
| 25 | 26 | #include <linux/interrupt.h> |
| 26 | 27 | #include <linux/mfd/tps65910.h> |
| 27 | 28 | |
| 28 | 29 | struct tps65910_rtc { |
| 29 | 30 | struct rtc_device *rtc; |
| 30 | − /* To store the list of enabled interrupts */ | |
| 31 | − u32 irqstat; | |
| 31 | + int irq; | |
| 32 | 32 | }; |
| 33 | 33 | |
| 34 | 34 | /* Total number of RTC registers needed to set time*/ |
| @@ -267,13 +267,14 @@ static int tps65910_rtc_probe(struct platform_device *pdev) · 232 unmodified lines | ||
| 267 | 267 | } |
| 268 | 268 | |
| 269 | 269 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, |
| 270 | − tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, | |
| 270 | + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, | |
| 271 | 271 | dev_name(&pdev->dev), &pdev->dev); |
| 272 | 272 | if (ret < 0) { |
| 273 | 273 | dev_err(&pdev->dev, "IRQ is not free.\n"); |
| 274 | 274 | return ret; |
| 275 | 275 | } |
| 276 | − device_init_wakeup(&pdev->dev, 1); | |
| 276 | + tps_rtc->irq = irq; | |
| 277 | + device_set_wakeup_capable(&pdev->dev, 1); | |
| 277 | 278 | |
| 278 | 279 | tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, |
| 279 | 280 | &tps65910_rtc_ops, THIS_MODULE); |
| @@ -304,49 +305,36 @@ static int tps65910_rtc_remove(struct platform_device *pdev) · 24 unmodified lines | ||
| 304 | 305 | } |
| 305 | 306 | |
| 306 | 307 | #ifdef CONFIG_PM_SLEEP |
| 307 | − | |
| 308 | 308 | static int tps65910_rtc_suspend(struct device *dev) |
| 309 | 309 | { |
| 310 | − struct tps65910 *tps = dev_get_drvdata(dev->parent); | |
| 311 | − u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; | |
| 312 | − int ret; | |
| 313 | − | |
| 314 | − /* Store current list of enabled interrupts*/ | |
| 315 | − ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, | |
| 316 | − &tps->rtc->irqstat); | |
| 317 | − if (ret < 0) | |
| 318 | − return ret; | |
| 310 | + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); | |
| 319 | 311 | |
| 320 | − /* Enable RTC ALARM interrupt only */ | |
| 321 | − return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm); | |
| 312 | + if (device_may_wakeup(dev)) | |
| 313 | + enable_irq_wake(tps_rtc->irq); | |
| 314 | + return 0; | |
| 322 | 315 | } |
| 323 | 316 | |
| 324 | 317 | static int tps65910_rtc_resume(struct device *dev) |
| 325 | 318 | { |
| 326 | − struct tps65910 *tps = dev_get_drvdata(dev->parent); | |
| 319 | + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); | |
| 327 | 320 | |
| 328 | − /* Restore list of enabled interrupts before suspend */ | |
| 329 | − return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, | |
| 330 | − tps->rtc->irqstat); | |
| 321 | + if (device_may_wakeup(dev)) | |
| 322 | + disable_irq_wake(tps_rtc->irq); | |
| 323 | + return 0; | |
| 331 | 324 | } |
| 325 | +#endif | |
| 332 | 326 | |
| 333 | 327 | static const struct dev_pm_ops tps65910_rtc_pm_ops = { |
| 334 | − .suspend = tps65910_rtc_suspend, | |
| 335 | − .resume = tps65910_rtc_resume, | |
| 328 | + SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume) | |
| 336 | 329 | }; |
| 337 | 330 | |
| 338 | −#define DEV_PM_OPS (&tps65910_rtc_pm_ops) | |
| 339 | −#else | |
| 340 | −#define DEV_PM_OPS NULL | |
| 341 | −#endif | |
| 342 | − | |
| 343 | 331 | static struct platform_driver tps65910_rtc_driver = { |
| 344 | 332 | .probe = tps65910_rtc_probe, |
| 345 | 333 | .remove = tps65910_rtc_remove, |
| 346 | 334 | .driver = { |
| 347 | 335 | .owner = THIS_MODULE, |
| 348 | 336 | .name = "tps65910-rtc", |
| 349 | − .pm = DEV_PM_OPS, | |
| 337 | + .pm = &tps65910_rtc_pm_ops, | |
| 350 | 338 | }, |
| 351 | 339 | }; |
| 352 | 340 | |
| @@ -0,0 +1,349 @@ | ||
| 1 | +/* | |
| 2 | + * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver | |
| 3 | + * | |
| 4 | + * RTC driver for TI TPS80031/TPS80032 Fully Integrated | |
| 5 | + * Power Management with Power Path and Battery Charger | |
| 6 | + * | |
| 7 | + * Copyright (c) 2012, NVIDIA Corporation. | |
| 8 | + * | |
| 9 | + * Author: Laxman Dewangan <ldewangan@nvidia.com> | |
| 10 | + * | |
| 11 | + * This program is free software; you can redistribute it and/or | |
| 12 | + * modify it under the terms of the GNU General Public License as | |
| 13 | + * published by the Free Software Foundation version 2. | |
| 14 | + * | |
| 15 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | |
| 16 | + * whether express or implied; without even the implied warranty of | |
| 17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 18 | + * General Public License for more details. | |
| 19 | + * | |
| 20 | + * You should have received a copy of the GNU General Public License | |
| 21 | + * along with this program; if not, write to the Free Software | |
| 22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
| 23 | + * 02111-1307, USA | |
| 24 | + */ | |
| 25 | + | |
| 26 | +#include <linux/bcd.h> | |
| 27 | +#include <linux/device.h> | |
| 28 | +#include <linux/err.h> | |
| 29 | +#include <linux/init.h> | |
| 30 | +#include <linux/kernel.h> | |
| 31 | +#include <linux/module.h> | |
| 32 | +#include <linux/mfd/tps80031.h> | |
| 33 | +#include <linux/platform_device.h> | |
| 34 | +#include <linux/pm.h> | |
| 35 | +#include <linux/rtc.h> | |
| 36 | +#include <linux/slab.h> | |
| 37 | + | |
| 38 | +#define ENABLE_ALARM_INT 0x08 | |
| 39 | +#define ALARM_INT_STATUS 0x40 | |
| 40 | + | |
| 41 | +/** | |
| 42 | + * Setting bit to 1 in STOP_RTC will run the RTC and | |
| 43 | + * setting this bit to 0 will freeze RTC. | |
| 44 | + */ | |
| 45 | +#define STOP_RTC 0x1 | |
| 46 | + | |
| 47 | +/* Power on reset Values of RTC registers */ | |
| 48 | +#define TPS80031_RTC_POR_YEAR 0 | |
| 49 | +#define TPS80031_RTC_POR_MONTH 1 | |
| 50 | +#define TPS80031_RTC_POR_DAY 1 | |
| 51 | + | |
| 52 | +/* Numbers of registers for time and alarms */ | |
| 53 | +#define TPS80031_RTC_TIME_NUM_REGS 7 | |
| 54 | +#define TPS80031_RTC_ALARM_NUM_REGS 6 | |
| 55 | + | |
| 56 | +/** | |
| 57 | + * PMU RTC have only 2 nibbles to store year information, so using an | |
| 58 | + * offset of 100 to set the base year as 2000 for our driver. | |
| 59 | + */ | |
| 60 | +#define RTC_YEAR_OFFSET 100 | |
| 61 | + | |
| 62 | +struct tps80031_rtc { | |
| 63 | + struct rtc_device *rtc; | |
| 64 | + int irq; | |
| 65 | +}; | |
| 66 | + | |
| 67 | +static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
| 68 | +{ | |
| 69 | + u8 buff[TPS80031_RTC_TIME_NUM_REGS]; | |
| 70 | + int ret; | |
| 71 | + | |
| 72 | + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, | |
| 73 | + TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff); | |
| 74 | + if (ret < 0) { | |
| 75 | + dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret); | |
| 76 | + return ret; | |
| 77 | + } | |
| 78 | + | |
| 79 | + tm->tm_sec = bcd2bin(buff[0]); | |
| 80 | + tm->tm_min = bcd2bin(buff[1]); | |
| 81 | + tm->tm_hour = bcd2bin(buff[2]); | |
| 82 | + tm->tm_mday = bcd2bin(buff[3]); | |
| 83 | + tm->tm_mon = bcd2bin(buff[4]) - 1; | |
| 84 | + tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; | |
| 85 | + tm->tm_wday = bcd2bin(buff[6]); | |
| 86 | + return 0; | |
| 87 | +} | |
| 88 | + | |
| 89 | +static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
| 90 | +{ | |
| 91 | + u8 buff[7]; | |
| 92 | + int ret; | |
| 93 | + | |
| 94 | + buff[0] = bin2bcd(tm->tm_sec); | |
| 95 | + buff[1] = bin2bcd(tm->tm_min); | |
| 96 | + buff[2] = bin2bcd(tm->tm_hour); | |
| 97 | + buff[3] = bin2bcd(tm->tm_mday); | |
| 98 | + buff[4] = bin2bcd(tm->tm_mon + 1); | |
| 99 | + buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET); | |
| 100 | + buff[6] = bin2bcd(tm->tm_wday); | |
| 101 | + | |
| 102 | + /* Stop RTC while updating the RTC time registers */ | |
| 103 | + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, | |
| 104 | + TPS80031_RTC_CTRL_REG, STOP_RTC); | |
| 105 | + if (ret < 0) { | |
| 106 | + dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret); | |
| 107 | + return ret; | |
| 108 | + } | |
| 109 | + | |
| 110 | + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, | |
| 111 | + TPS80031_SECONDS_REG, | |
| 112 | + TPS80031_RTC_TIME_NUM_REGS, buff); | |
| 113 | + if (ret < 0) { | |
| 114 | + dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret); | |
| 115 | + return ret; | |
| 116 | + } | |
| 117 | + | |
| 118 | + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, | |
| 119 | + TPS80031_RTC_CTRL_REG, STOP_RTC); | |
| 120 | + if (ret < 0) | |
| 121 | + dev_err(dev->parent, "Start RTC failed, err = %d\n", ret); | |
| 122 | + return ret; | |
| 123 | +} | |
| 124 | + | |
| 125 | +static int tps80031_rtc_alarm_irq_enable(struct device *dev, | |
| 126 | + unsigned int enable) | |
| 127 | +{ | |
| 128 | + int ret; | |
| 129 | + | |
| 130 | + if (enable) | |
| 131 | + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, | |
| 132 | + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); | |
| 133 | + else | |
| 134 | + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, | |
| 135 | + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); | |
| 136 | + if (ret < 0) { | |
| 137 | + dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret); | |
| 138 | + return ret; | |
| 139 | + } | |
| 140 | + return 0; | |
| 141 | +} | |
| 142 | + | |
| 143 | +static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 144 | +{ | |
| 145 | + u8 buff[TPS80031_RTC_ALARM_NUM_REGS]; | |
| 146 | + int ret; | |
| 147 | + | |
| 148 | + buff[0] = bin2bcd(alrm->time.tm_sec); | |
| 149 | + buff[1] = bin2bcd(alrm->time.tm_min); | |
| 150 | + buff[2] = bin2bcd(alrm->time.tm_hour); | |
| 151 | + buff[3] = bin2bcd(alrm->time.tm_mday); | |
| 152 | + buff[4] = bin2bcd(alrm->time.tm_mon + 1); | |
| 153 | + buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET); | |
| 154 | + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, | |
| 155 | + TPS80031_ALARM_SECONDS_REG, | |
| 156 | + TPS80031_RTC_ALARM_NUM_REGS, buff); | |
| 157 | + if (ret < 0) { | |
| 158 | + dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret); | |
| 159 | + return ret; | |
| 160 | + } | |
| 161 | + return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled); | |
| 162 | +} | |
| 163 | + | |
| 164 | +static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
| 165 | +{ | |
| 166 | + u8 buff[6]; | |
| 167 | + int ret; | |
| 168 | + | |
| 169 | + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, | |
| 170 | + TPS80031_ALARM_SECONDS_REG, | |
| 171 | + TPS80031_RTC_ALARM_NUM_REGS, buff); | |
| 172 | + if (ret < 0) { | |
| 173 | + dev_err(dev->parent, | |
| 174 | + "reading RTC_ALARM failed, err = %d\n", ret); | |
| 175 | + return ret; | |
| 176 | + } | |
| 177 | + | |
| 178 | + alrm->time.tm_sec = bcd2bin(buff[0]); | |
| 179 | + alrm->time.tm_min = bcd2bin(buff[1]); | |
| 180 | + alrm->time.tm_hour = bcd2bin(buff[2]); | |
| 181 | + alrm->time.tm_mday = bcd2bin(buff[3]); | |
| 182 | + alrm->time.tm_mon = bcd2bin(buff[4]) - 1; | |
| 183 | + alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; | |
| 184 | + return 0; | |
| 185 | +} | |
| 186 | + | |
| 187 | +static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc) | |
| 188 | +{ | |
| 189 | + int ret; | |
| 190 | + u8 buf; | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * As per datasheet, A dummy read of this RTC_STATUS_REG register | |
| 194 | + * is necessary before each I2C read in order to update the status | |
| 195 | + * register value. | |
| 196 | + */ | |
| 197 | + ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1, | |
| 198 | + TPS80031_RTC_STATUS_REG, &buf); | |
| 199 | + if (ret < 0) { | |
| 200 | + dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret); | |
| 201 | + return ret; | |
| 202 | + } | |
| 203 | + | |
| 204 | + /* clear Alarm status bits.*/ | |
| 205 | + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, | |
| 206 | + TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS); | |
| 207 | + if (ret < 0) { | |
| 208 | + dev_err(dev, "clear Alarm INT failed, err = %d\n", ret); | |
| 209 | + return ret; | |
| 210 | + } | |
| 211 | + return 0; | |
| 212 | +} | |
| 213 | + | |
| 214 | +static irqreturn_t tps80031_rtc_irq(int irq, void *data) | |
| 215 | +{ | |
| 216 | + struct device *dev = data; | |
| 217 | + struct tps80031_rtc *rtc = dev_get_drvdata(dev); | |
| 218 | + int ret; | |
| 219 | + | |
| 220 | + ret = clear_alarm_int_status(dev, rtc); | |
| 221 | + if (ret < 0) | |
| 222 | + return ret; | |
| 223 | + | |
| 224 | + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); | |
| 225 | + return IRQ_HANDLED; | |
| 226 | +} | |
| 227 | + | |
| 228 | +static const struct rtc_class_ops tps80031_rtc_ops = { | |
| 229 | + .read_time = tps80031_rtc_read_time, | |
| 230 | + .set_time = tps80031_rtc_set_time, | |
| 231 | + .set_alarm = tps80031_rtc_set_alarm, | |
| 232 | + .read_alarm = tps80031_rtc_read_alarm, | |
| 233 | + .alarm_irq_enable = tps80031_rtc_alarm_irq_enable, | |
| 234 | +}; | |
| 235 | + | |
| 236 | +static int tps80031_rtc_probe(struct platform_device *pdev) | |
| 237 | +{ | |
| 238 | + struct tps80031_rtc *rtc; | |
| 239 | + struct rtc_time tm; | |
| 240 | + int ret; | |
| 241 | + | |
| 242 | + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); | |
| 243 | + if (!rtc) | |
| 244 | + return -ENOMEM; | |
| 245 | + | |
| 246 | + rtc->irq = platform_get_irq(pdev, 0); | |
| 247 | + platform_set_drvdata(pdev, rtc); | |
| 248 | + | |
| 249 | + /* Start RTC */ | |
| 250 | + ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1, | |
| 251 | + TPS80031_RTC_CTRL_REG, STOP_RTC); | |
| 252 | + if (ret < 0) { | |
| 253 | + dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret); | |
| 254 | + return ret; | |
| 255 | + } | |
| 256 | + | |
| 257 | + /* If RTC have POR values, set time 01:01:2000 */ | |
| 258 | + tps80031_rtc_read_time(&pdev->dev, &tm); | |
| 259 | + if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) && | |
| 260 | + (tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) && | |
| 261 | + (tm.tm_mday == TPS80031_RTC_POR_DAY)) { | |
| 262 | + tm.tm_year = 2000; | |
| 263 | + tm.tm_mday = 1; | |
| 264 | + tm.tm_mon = 1; | |
| 265 | + ret = tps80031_rtc_set_time(&pdev->dev, &tm); | |
| 266 | + if (ret < 0) { | |
| 267 | + dev_err(&pdev->dev, | |
| 268 | + "RTC set time failed, err = %d\n", ret); | |
| 269 | + return ret; | |
| 270 | + } | |
| 271 | + } | |
| 272 | + | |
| 273 | + /* Clear alarm intretupt status if it is there */ | |
| 274 | + ret = clear_alarm_int_status(&pdev->dev, rtc); | |
| 275 | + if (ret < 0) { | |
| 276 | + dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret); | |
| 277 | + return ret; | |
| 278 | + } | |
| 279 | + | |
| 280 | + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, | |
| 281 | + &tps80031_rtc_ops, THIS_MODULE); | |
| 282 | + if (IS_ERR(rtc->rtc)) { | |
| 283 | + ret = PTR_ERR(rtc->rtc); | |
| 284 | + dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret); | |
| 285 | + return ret; | |
| 286 | + } | |
| 287 | + | |
| 288 | + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | |
| 289 | + tps80031_rtc_irq, | |
| 290 | + IRQF_ONESHOT | IRQF_EARLY_RESUME, | |
| 291 | + dev_name(&pdev->dev), rtc); | |
| 292 | + if (ret < 0) { | |
| 293 | + dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", | |
| 294 | + rtc->irq, ret); | |
| 295 | + rtc_device_unregister(rtc->rtc); | |
| 296 | + return ret; | |
| 297 | + } | |
| 298 | + device_set_wakeup_capable(&pdev->dev, 1); | |
| 299 | + return 0; | |
| 300 | +} | |
| 301 | + | |
| 302 | +static int tps80031_rtc_remove(struct platform_device *pdev) | |
| 303 | +{ | |
| 304 | + struct tps80031_rtc *rtc = platform_get_drvdata(pdev); | |
| 305 | + | |
| 306 | + rtc_device_unregister(rtc->rtc); | |
| 307 | + return 0; | |
| 308 | +} | |
| 309 | + | |
| 310 | +#ifdef CONFIG_PM_SLEEP | |
| 311 | +static int tps80031_rtc_suspend(struct device *dev) | |
| 312 | +{ | |
| 313 | + struct tps80031_rtc *rtc = dev_get_drvdata(dev); | |
| 314 | + | |
| 315 | + if (device_may_wakeup(dev)) | |
| 316 | + enable_irq_wake(rtc->irq); | |
| 317 | + return 0; | |
| 318 | +} | |
| 319 | + | |
| 320 | +static int tps80031_rtc_resume(struct device *dev) | |
| 321 | +{ | |
| 322 | + struct tps80031_rtc *rtc = dev_get_drvdata(dev); | |
| 323 | + | |
| 324 | + if (device_may_wakeup(dev)) | |
| 325 | + disable_irq_wake(rtc->irq); | |
| 326 | + return 0; | |
| 327 | +}; | |
| 328 | +#endif | |
| 329 | + | |
| 330 | +static const struct dev_pm_ops tps80031_pm_ops = { | |
| 331 | + SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume) | |
| 332 | +}; | |
| 333 | + | |
| 334 | +static struct platform_driver tps80031_rtc_driver = { | |
| 335 | + .driver = { | |
| 336 | + .name = "tps80031-rtc", | |
| 337 | + .owner = THIS_MODULE, | |
| 338 | + .pm = &tps80031_pm_ops, | |
| 339 | + }, | |
| 340 | + .probe = tps80031_rtc_probe, | |
| 341 | + .remove = tps80031_rtc_remove, | |
| 342 | +}; | |
| 343 | + | |
| 344 | +module_platform_driver(tps80031_rtc_driver); | |
| 345 | + | |
| 346 | +MODULE_ALIAS("platform:tps80031-rtc"); | |
| 347 | +MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver"); | |
| 348 | +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | |
| 349 | +MODULE_LICENSE("GPL v2"); | |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <linux/bcd.h> |
| 28 | 28 | #include <linux/platform_device.h> |
| 29 | 29 | #include <linux/interrupt.h> |
| 30 | +#include <linux/of.h> | |
| 30 | 31 | |
| 31 | 32 | #include <linux/i2c/twl.h> |
| 32 | 33 | |
| @@ -588,11 +589,14 @@ static int twl_rtc_resume(struct platform_device *pdev) · 555 unmodified lines | ||
| 588 | 589 | #define twl_rtc_resume NULL |
| 589 | 590 | #endif |
| 590 | 591 | |
| 592 | +#ifdef CONFIG_OF | |
| 591 | 593 | static const struct of_device_id twl_rtc_of_match[] = { |
| 592 | 594 | {.compatible = "ti,twl4030-rtc", }, |
| 593 | 595 | { }, |
| 594 | 596 | }; |
| 595 | 597 | MODULE_DEVICE_TABLE(of, twl_rtc_of_match); |
| 598 | +#endif | |
| 599 | + | |
| 596 | 600 | MODULE_ALIAS("platform:twl_rtc"); |
| 597 | 601 | |
| 598 | 602 | static struct platform_driver twl4030rtc_driver = { |
| @@ -604,7 +608,7 @@ static struct platform_driver twl4030rtc_driver = { · 5 unmodified lines | ||
| 604 | 608 | .driver = { |
| 605 | 609 | .owner = THIS_MODULE, |
| 606 | 610 | .name = "twl_rtc", |
| 607 | − .of_match_table = twl_rtc_of_match, | |
| 611 | + .of_match_table = of_match_ptr(twl_rtc_of_match), | |
| 608 | 612 | }, |
| 609 | 613 | }; |
| 610 | 614 | |
| @@ -352,7 +352,7 @@ static int rtc_probe(struct platform_device *pdev) · 351 unmodified lines | ||
| 352 | 352 | disable_irq(aie_irq); |
| 353 | 353 | disable_irq(pie_irq); |
| 354 | 354 | |
| 355 | − printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n"); | |
| 355 | + dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); | |
| 356 | 356 | |
| 357 | 357 | return 0; |
| 358 | 358 | |
| @@ -231,20 +231,21 @@ static int vt8500_rtc_probe(struct platform_device *pdev) · 230 unmodified lines | ||
| 231 | 231 | return -ENXIO; |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | − vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, | |
| 235 | − resource_size(vt8500_rtc->res), | |
| 236 | − "vt8500-rtc"); | |
| 234 | + vt8500_rtc->res = devm_request_mem_region(&pdev->dev, | |
| 235 | + vt8500_rtc->res->start, | |
| 236 | + resource_size(vt8500_rtc->res), | |
| 237 | + "vt8500-rtc"); | |
| 237 | 238 | if (vt8500_rtc->res == NULL) { |
| 238 | 239 | dev_err(&pdev->dev, "failed to request I/O memory\n"); |
| 239 | 240 | return -EBUSY; |
| 240 | 241 | } |
| 241 | 242 | |
| 242 | − vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, | |
| 243 | + vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start, | |
| 243 | 244 | resource_size(vt8500_rtc->res)); |
| 244 | 245 | if (!vt8500_rtc->regbase) { |
| 245 | 246 | dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); |
| 246 | 247 | ret = -EBUSY; |
| 247 | − goto err_release; | |
| 248 | + goto err_return; | |
| 248 | 249 | } |
| 249 | 250 | |
| 250 | 251 | /* Enable RTC and set it to 24-hour mode */ |
| @@ -257,11 +258,11 @@ static int vt8500_rtc_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 257 | 258 | ret = PTR_ERR(vt8500_rtc->rtc); |
| 258 | 259 | dev_err(&pdev->dev, |
| 259 | 260 | "Failed to register RTC device -> %d\n", ret); |
| 260 | − goto err_unmap; | |
| 261 | + goto err_return; | |
| 261 | 262 | } |
| 262 | 263 | |
| 263 | − ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, | |
| 264 | − "rtc alarm", vt8500_rtc); | |
| 264 | + ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm, | |
| 265 | + vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc); | |
| 265 | 266 | if (ret < 0) { |
| 266 | 267 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", |
| 267 | 268 | vt8500_rtc->irq_alarm, ret); |
| @@ -272,11 +273,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 272 | 273 | |
| 273 | 274 | err_unreg: |
| 274 | 275 | rtc_device_unregister(vt8500_rtc->rtc); |
| 275 | −err_unmap: | |
| 276 | − iounmap(vt8500_rtc->regbase); | |
| 277 | −err_release: | |
| 278 | − release_mem_region(vt8500_rtc->res->start, | |
| 279 | − resource_size(vt8500_rtc->res)); | |
| 276 | +err_return: | |
| 280 | 277 | return ret; |
| 281 | 278 | } |
| 282 | 279 | |
| @@ -284,15 +281,10 @@ static int vt8500_rtc_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 284 | 281 | { |
| 285 | 282 | struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); |
| 286 | 283 | |
| 287 | − free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); | |
| 288 | − | |
| 289 | 284 | rtc_device_unregister(vt8500_rtc->rtc); |
| 290 | 285 | |
| 291 | 286 | /* Disable alarm matching */ |
| 292 | 287 | writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); |
| 293 | − iounmap(vt8500_rtc->regbase); | |
| 294 | − release_mem_region(vt8500_rtc->res->start, | |
| 295 | − resource_size(vt8500_rtc->res)); | |
| 296 | 288 | |
| 297 | 289 | platform_set_drvdata(pdev, NULL); |
| 298 | 290 | |
| @@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev) · 442 unmodified lines | ||
| 443 | 443 | goto err; |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | − ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq, | |
| 447 | − IRQF_TRIGGER_RISING, "RTC alarm", | |
| 448 | − wm831x_rtc); | |
| 446 | + ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, | |
| 447 | + wm831x_alm_irq, | |
| 448 | + IRQF_TRIGGER_RISING, "RTC alarm", | |
| 449 | + wm831x_rtc); | |
| 449 | 450 | if (ret != 0) { |
| 450 | 451 | dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", |
| 451 | 452 | alm_irq, ret); |
| @@ -462,9 +463,7 @@ err: · 10 unmodified lines | ||
| 462 | 463 | static int wm831x_rtc_remove(struct platform_device *pdev) |
| 463 | 464 | { |
| 464 | 465 | struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); |
| 465 | − int alm_irq = platform_get_irq_byname(pdev, "ALM"); | |
| 466 | 466 | |
| 467 | − free_irq(alm_irq, wm831x_rtc); | |
| 468 | 467 | rtc_device_unregister(wm831x_rtc->rtc); |
| 469 | 468 | |
| 470 | 469 | return 0; |
| @@ -364,7 +364,7 @@ config FB_SA1100 · 363 unmodified lines | ||
| 364 | 364 | Y here. |
| 365 | 365 | |
| 366 | 366 | config FB_IMX |
| 367 | − tristate "Freescale i.MX LCD support" | |
| 367 | + tristate "Freescale i.MX1/21/25/27 LCD support" | |
| 368 | 368 | depends on FB && IMX_HAVE_PLATFORM_IMX_FB |
| 369 | 369 | select FB_CFB_FILLRECT |
| 370 | 370 | select FB_CFB_COPYAREA |
| @@ -2025,7 +2025,8 @@ config FB_TMIO_ACCELL · 1654 unmodified lines | ||
| 2025 | 2025 | |
| 2026 | 2026 | config FB_S3C |
| 2027 | 2027 | tristate "Samsung S3C framebuffer support" |
| 2028 | − depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0) | |
| 2028 | + depends on FB && (CPU_S3C2416 || ARCH_S3C64XX || ARCH_S5P64X0 || \ | |
| 2029 | + ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) | |
| 2029 | 2030 | select FB_CFB_FILLRECT |
| 2030 | 2031 | select FB_CFB_COPYAREA |
| 2031 | 2032 | select FB_CFB_IMAGEBLIT |
| @@ -2183,6 +2184,15 @@ config FB_XILINX · 151 unmodified lines | ||
| 2183 | 2184 | framebuffer. ML300 carries a 640*480 LCD display on the board, |
| 2184 | 2185 | ML403 uses a standard DB15 VGA connector. |
| 2185 | 2186 | |
| 2187 | +config FB_GOLDFISH | |
| 2188 | + tristate "Goldfish Framebuffer" | |
| 2189 | + depends on FB | |
| 2190 | + select FB_CFB_FILLRECT | |
| 2191 | + select FB_CFB_COPYAREA | |
| 2192 | + select FB_CFB_IMAGEBLIT | |
| 2193 | + ---help--- | |
| 2194 | + Framebuffer driver for Goldfish Virtual Platform | |
| 2195 | + | |
| 2186 | 2196 | config FB_COBALT |
| 2187 | 2197 | tristate "Cobalt server LCD frame buffer support" |
| 2188 | 2198 | depends on FB && (MIPS_COBALT || MIPS_SEAD3) |
| @@ -2422,6 +2432,7 @@ config FB_PUV3_UNIGFX · 233 unmodified lines | ||
| 2422 | 2432 | source "drivers/video/omap/Kconfig" |
| 2423 | 2433 | source "drivers/video/omap2/Kconfig" |
| 2424 | 2434 | source "drivers/video/exynos/Kconfig" |
| 2435 | +source "drivers/video/mmp/Kconfig" | |
| 2425 | 2436 | source "drivers/video/backlight/Kconfig" |
| 2426 | 2437 | |
| 2427 | 2438 | if VT |
| @@ -98,6 +98,7 @@ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o · 97 unmodified lines | ||
| 98 | 98 | obj-$(CONFIG_FB_PVR2) += pvr2fb.o |
| 99 | 99 | obj-$(CONFIG_FB_VOODOO1) += sstfb.o |
| 100 | 100 | obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o |
| 101 | +obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o | |
| 101 | 102 | obj-$(CONFIG_FB_68328) += 68328fb.o |
| 102 | 103 | obj-$(CONFIG_FB_GBE) += gbefb.o |
| 103 | 104 | obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o |
| @@ -105,6 +106,7 @@ obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o · 1 unmodified line | ||
| 105 | 106 | obj-$(CONFIG_FB_PXA) += pxafb.o |
| 106 | 107 | obj-$(CONFIG_FB_PXA168) += pxa168fb.o |
| 107 | 108 | obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o |
| 109 | +obj-$(CONFIG_MMP_DISP) += mmp/ | |
| 108 | 110 | obj-$(CONFIG_FB_W100) += w100fb.o |
| 109 | 111 | obj-$(CONFIG_FB_TMIO) += tmiofb.o |
| 110 | 112 | obj-$(CONFIG_FB_AU1100) += au1100fb.o |
| @@ -165,8 +165,10 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, · 164 unmodified lines | ||
| 165 | 165 | struct pm860x_backlight_data *data, |
| 166 | 166 | char *name) |
| 167 | 167 | { |
| 168 | − struct device_node *nproot = pdev->dev.parent->of_node, *np; | |
| 168 | + struct device_node *nproot, *np; | |
| 169 | 169 | int iset = 0; |
| 170 | + | |
| 171 | + nproot = of_node_get(pdev->dev.parent->of_node); | |
| 170 | 172 | if (!nproot) |
| 171 | 173 | return -ENODEV; |
| 172 | 174 | nproot = of_find_node_by_name(nproot, "backlights"); |
| @@ -184,6 +186,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, · 11 unmodified lines | ||
| 184 | 186 | break; |
| 185 | 187 | } |
| 186 | 188 | } |
| 189 | + of_node_put(nproot); | |
| 187 | 190 | return 0; |
| 188 | 191 | } |
| 189 | 192 | #else |
| @@ -126,6 +126,21 @@ config LCD_AMS369FG06 · 125 unmodified lines | ||
| 126 | 126 | If you have an AMS369FG06 AMOLED Panel, say Y to enable its |
| 127 | 127 | LCD control driver. |
| 128 | 128 | |
| 129 | +config LCD_LMS501KF03 | |
| 130 | + tristate "LMS501KF03 LCD Driver" | |
| 131 | + depends on SPI | |
| 132 | + default n | |
| 133 | + help | |
| 134 | + If you have an LMS501KF03 LCD Panel, say Y to enable its | |
| 135 | + LCD control driver. | |
| 136 | + | |
| 137 | +config LCD_HX8357 | |
| 138 | + tristate "Himax HX-8357 LCD Driver" | |
| 139 | + depends on SPI | |
| 140 | + help | |
| 141 | + If you have a HX-8357 LCD panel, say Y to enable its LCD control | |
| 142 | + driver. | |
| 143 | + | |
| 129 | 144 | endif # LCD_CLASS_DEVICE |
| 130 | 145 | |
| 131 | 146 | # |
| @@ -366,7 +381,7 @@ config BACKLIGHT_LP855X · 234 unmodified lines | ||
| 366 | 381 | tristate "Backlight driver for TI LP855X" |
| 367 | 382 | depends on BACKLIGHT_CLASS_DEVICE && I2C |
| 368 | 383 | help |
| 369 | − This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556 | |
| 384 | + This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557 | |
| 370 | 385 | backlight driver. |
| 371 | 386 | |
| 372 | 387 | config BACKLIGHT_OT200 |
| @@ -390,6 +405,13 @@ config BACKLIGHT_TPS65217 · 17 unmodified lines | ||
| 390 | 405 | If you have a Texas Instruments TPS65217 say Y to enable the |
| 391 | 406 | backlight driver. |
| 392 | 407 | |
| 408 | +config BACKLIGHT_AS3711 | |
| 409 | + tristate "AS3711 Backlight" | |
| 410 | + depends on BACKLIGHT_CLASS_DEVICE && MFD_AS3711 | |
| 411 | + help | |
| 412 | + If you have an Austrian Microsystems AS3711 say Y to enable the | |
| 413 | + backlight driver. | |
| 414 | + | |
| 393 | 415 | endif # BACKLIGHT_CLASS_DEVICE |
| 394 | 416 | |
| 395 | 417 | endif # BACKLIGHT_LCD_SUPPORT |
| @@ -1,47 +1,50 @@ | ||
| 1 | 1 | # Backlight & LCD drivers |
| 2 | 2 | |
| 3 | −obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o | |
| 4 | −obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o | |
| 5 | −obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o | |
| 6 | −obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o | |
| 7 | −obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o | |
| 8 | −obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o | |
| 9 | −obj-$(CONFIG_LCD_ILI9320) += ili9320.o | |
| 10 | −obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o | |
| 11 | −obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o | |
| 12 | −obj-$(CONFIG_LCD_TDO24M) += tdo24m.o | |
| 13 | −obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o | |
| 14 | −obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o | |
| 15 | −obj-$(CONFIG_LCD_LD9040) += ld9040.o | |
| 16 | −obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o | |
| 3 | +obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o | |
| 4 | +obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o | |
| 5 | +obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o | |
| 6 | +obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o | |
| 7 | +obj-$(CONFIG_LCD_HX8357) += hx8357.o | |
| 8 | +obj-$(CONFIG_LCD_ILI9320) += ili9320.o | |
| 9 | +obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o | |
| 10 | +obj-$(CONFIG_LCD_LD9040) += ld9040.o | |
| 11 | +obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o | |
| 12 | +obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o | |
| 13 | +obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o | |
| 14 | +obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o | |
| 15 | +obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o | |
| 16 | +obj-$(CONFIG_LCD_TDO24M) += tdo24m.o | |
| 17 | +obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o | |
| 18 | +obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o | |
| 17 | 19 | |
| 18 | −obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | |
| 19 | −obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | |
| 20 | −obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o | |
| 21 | −obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o | |
| 22 | −obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o | |
| 23 | −obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o | |
| 24 | −obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o | |
| 25 | −obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o | |
| 26 | −obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o | |
| 27 | −obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o | |
| 28 | −obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o | |
| 29 | −obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o | |
| 30 | −obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o | |
| 31 | −obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o | |
| 32 | −obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o | |
| 33 | −obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o | |
| 34 | −obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o | |
| 35 | −obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o | |
| 36 | −obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o | |
| 37 | −obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o | |
| 38 | −obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o | |
| 39 | −obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o | |
| 40 | −obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o | |
| 41 | −obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o | |
| 42 | −obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o | |
| 43 | −obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o | |
| 20 | +obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o | |
| 21 | +obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o | |
| 22 | +obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o | |
| 23 | +obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o | |
| 24 | +obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o | |
| 25 | +obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o | |
| 26 | +obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o | |
| 27 | +obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | |
| 28 | +obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o | |
| 29 | +obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | |
| 30 | +obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o | |
| 31 | +obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o | |
| 32 | +obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o | |
| 33 | +obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o | |
| 34 | +obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o | |
| 35 | +obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o | |
| 36 | +obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o | |
| 37 | +obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o | |
| 38 | +obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o | |
| 39 | +obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o | |
| 40 | +obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o | |
| 41 | +obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o | |
| 42 | +obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o | |
| 43 | +obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o | |
| 44 | +obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o | |
| 44 | 45 | obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o |
| 45 | −obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o | |
| 46 | −obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o | |
| 47 | −obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o | |
| 46 | +obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o | |
| 47 | +obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o | |
| 48 | +obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o | |
| 49 | +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o | |
| 50 | +obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o | |
| @@ -74,7 +74,7 @@ static int aat2870_bl_get_brightness(struct backlight_device *bd) · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | static int aat2870_bl_update_status(struct backlight_device *bd) |
| 76 | 76 | { |
| 77 | − struct aat2870_bl_driver_data *aat2870_bl = dev_get_drvdata(&bd->dev); | |
| 77 | + struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd); | |
| 78 | 78 | struct aat2870_data *aat2870 = |
| 79 | 79 | dev_get_drvdata(aat2870_bl->pdev->dev.parent); |
| 80 | 80 | int brightness = bd->props.brightness; |
| @@ -783,7 +783,7 @@ static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) · 782 unmodified lines | ||
| 783 | 783 | |
| 784 | 784 | static int adp8860_i2c_resume(struct i2c_client *client) |
| 785 | 785 | { |
| 786 | − adp8860_set_bits(client, ADP8860_MDCR, NSTBY); | |
| 786 | + adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN); | |
| 787 | 787 | |
| 788 | 788 | return 0; |
| 789 | 789 | } |
| @@ -957,7 +957,7 @@ static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message) · 956 unmodified lines | ||
| 957 | 957 | |
| 958 | 958 | static int adp8870_i2c_resume(struct i2c_client *client) |
| 959 | 959 | { |
| 960 | − adp8870_set_bits(client, ADP8870_MDCR, NSTBY); | |
| 960 | + adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN); | |
| 961 | 961 | |
| 962 | 962 | return 0; |
| 963 | 963 | } |
| @@ -10,25 +10,16 @@ · 9 unmodified lines | ||
| 10 | 10 | * under the terms of the GNU General Public License as published by the |
| 11 | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
| 12 | 12 | * option) any later version. |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, but | |
| 15 | − * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 17 | − * General Public License for more details. | |
| 18 | − * | |
| 19 | − * You should have received a copy of the GNU General Public License along | |
| 20 | − * with this program; if not, write to the Free Software Foundation, Inc., | |
| 21 | − * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 22 | 13 | */ |
| 23 | 14 | |
| 24 | −#include <linux/wait.h> | |
| 25 | −#include <linux/module.h> | |
| 26 | −#include <linux/fb.h> | |
| 15 | +#include <linux/backlight.h> | |
| 27 | 16 | #include <linux/delay.h> |
| 17 | +#include <linux/fb.h> | |
| 28 | 18 | #include <linux/gpio.h> |
| 29 | −#include <linux/spi/spi.h> | |
| 30 | 19 | #include <linux/lcd.h> |
| 31 | −#include <linux/backlight.h> | |
| 20 | +#include <linux/module.h> | |
| 21 | +#include <linux/spi/spi.h> | |
| 22 | +#include <linux/wait.h> | |
| 32 | 23 | |
| 33 | 24 | #define SLEEPMSEC 0x1000 |
| 34 | 25 | #define ENDDEF 0x2000 |
| @@ -210,8 +201,9 @@ static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd, · 175 unmodified lines | ||
| 210 | 201 | ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]); |
| 211 | 202 | if (ret) |
| 212 | 203 | break; |
| 213 | − } else | |
| 214 | − mdelay(wbuf[i+1]); | |
| 204 | + } else { | |
| 205 | + msleep(wbuf[i+1]); | |
| 206 | + } | |
| 215 | 207 | i += 2; |
| 216 | 208 | } |
| 217 | 209 | |
| @@ -313,41 +305,32 @@ static int ams369fg06_ldi_disable(struct ams369fg06 *lcd) · 95 unmodified lines | ||
| 313 | 305 | |
| 314 | 306 | static int ams369fg06_power_is_on(int power) |
| 315 | 307 | { |
| 316 | − return ((power) <= FB_BLANK_NORMAL); | |
| 308 | + return power <= FB_BLANK_NORMAL; | |
| 317 | 309 | } |
| 318 | 310 | |
| 319 | 311 | static int ams369fg06_power_on(struct ams369fg06 *lcd) |
| 320 | 312 | { |
| 321 | 313 | int ret = 0; |
| 322 | − struct lcd_platform_data *pd = NULL; | |
| 323 | − struct backlight_device *bd = NULL; | |
| 314 | + struct lcd_platform_data *pd; | |
| 315 | + struct backlight_device *bd; | |
| 324 | 316 | |
| 325 | 317 | pd = lcd->lcd_pd; |
| 326 | − if (!pd) { | |
| 327 | − dev_err(lcd->dev, "platform data is NULL.\n"); | |
| 328 | − return -EFAULT; | |
| 329 | − } | |
| 330 | − | |
| 331 | 318 | bd = lcd->bd; |
| 332 | − if (!bd) { | |
| 333 | − dev_err(lcd->dev, "backlight device is NULL.\n"); | |
| 334 | − return -EFAULT; | |
| 335 | − } | |
| 336 | 319 | |
| 337 | 320 | if (!pd->power_on) { |
| 338 | 321 | dev_err(lcd->dev, "power_on is NULL.\n"); |
| 339 | − return -EFAULT; | |
| 322 | + return -EINVAL; | |
| 340 | 323 | } else { |
| 341 | 324 | pd->power_on(lcd->ld, 1); |
| 342 | − mdelay(pd->power_on_delay); | |
| 325 | + msleep(pd->power_on_delay); | |
| 343 | 326 | } |
| 344 | 327 | |
| 345 | 328 | if (!pd->reset) { |
| 346 | 329 | dev_err(lcd->dev, "reset is NULL.\n"); |
| 347 | − return -EFAULT; | |
| 330 | + return -EINVAL; | |
| 348 | 331 | } else { |
| 349 | 332 | pd->reset(lcd->ld); |
| 350 | − mdelay(pd->reset_delay); | |
| 333 | + msleep(pd->reset_delay); | |
| 351 | 334 | } |
| 352 | 335 | |
| 353 | 336 | ret = ams369fg06_ldi_init(lcd); |
| @@ -374,14 +357,10 @@ static int ams369fg06_power_on(struct ams369fg06 *lcd) · 20 unmodified lines | ||
| 374 | 357 | |
| 375 | 358 | static int ams369fg06_power_off(struct ams369fg06 *lcd) |
| 376 | 359 | { |
| 377 | − int ret = 0; | |
| 378 | − struct lcd_platform_data *pd = NULL; | |
| 360 | + int ret; | |
| 361 | + struct lcd_platform_data *pd; | |
| 379 | 362 | |
| 380 | 363 | pd = lcd->lcd_pd; |
| 381 | − if (!pd) { | |
| 382 | − dev_err(lcd->dev, "platform data is NULL\n"); | |
| 383 | − return -EFAULT; | |
| 384 | − } | |
| 385 | 364 | |
| 386 | 365 | ret = ams369fg06_ldi_disable(lcd); |
| 387 | 366 | if (ret) { |
| @@ -389,13 +368,9 @@ static int ams369fg06_power_off(struct ams369fg06 *lcd) · 1 unmodified line | ||
| 389 | 368 | return -EIO; |
| 390 | 369 | } |
| 391 | 370 | |
| 392 | − mdelay(pd->power_off_delay); | |
| 371 | + msleep(pd->power_off_delay); | |
| 393 | 372 | |
| 394 | − if (!pd->power_on) { | |
| 395 | − dev_err(lcd->dev, "power_on is NULL.\n"); | |
| 396 | − return -EFAULT; | |
| 397 | − } else | |
| 398 | − pd->power_on(lcd->ld, 0); | |
| 373 | + pd->power_on(lcd->ld, 0); | |
| 399 | 374 | |
| 400 | 375 | return 0; |
| 401 | 376 | } |
| @@ -446,7 +421,7 @@ static int ams369fg06_set_brightness(struct backlight_device *bd) · 44 unmodified lines | ||
| 446 | 421 | { |
| 447 | 422 | int ret = 0; |
| 448 | 423 | int brightness = bd->props.brightness; |
| 449 | − struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev); | |
| 424 | + struct ams369fg06 *lcd = bl_get_data(bd); | |
| 450 | 425 | |
| 451 | 426 | if (brightness < MIN_BRIGHTNESS || |
| 452 | 427 | brightness > bd->props.max_brightness) { |
| @@ -501,7 +476,7 @@ static int ams369fg06_probe(struct spi_device *spi) · 48 unmodified lines | ||
| 501 | 476 | lcd->lcd_pd = spi->dev.platform_data; |
| 502 | 477 | if (!lcd->lcd_pd) { |
| 503 | 478 | dev_err(&spi->dev, "platform data is NULL\n"); |
| 504 | − return -EFAULT; | |
| 479 | + return -EINVAL; | |
| 505 | 480 | } |
| 506 | 481 | |
| 507 | 482 | ld = lcd_device_register("ams369fg06", &spi->dev, lcd, |
| @@ -534,10 +509,11 @@ static int ams369fg06_probe(struct spi_device *spi) · 26 unmodified lines | ||
| 534 | 509 | lcd->power = FB_BLANK_POWERDOWN; |
| 535 | 510 | |
| 536 | 511 | ams369fg06_power(lcd, FB_BLANK_UNBLANK); |
| 537 | − } else | |
| 512 | + } else { | |
| 538 | 513 | lcd->power = FB_BLANK_UNBLANK; |
| 514 | + } | |
| 539 | 515 | |
| 540 | − dev_set_drvdata(&spi->dev, lcd); | |
| 516 | + spi_set_drvdata(spi, lcd); | |
| 541 | 517 | |
| 542 | 518 | dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n"); |
| 543 | 519 | |
| @@ -550,7 +526,7 @@ out_lcd_unregister: · 6 unmodified lines | ||
| 550 | 526 | |
| 551 | 527 | static int ams369fg06_remove(struct spi_device *spi) |
| 552 | 528 | { |
| 553 | − struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | |
| 529 | + struct ams369fg06 *lcd = spi_get_drvdata(spi); | |
| 554 | 530 | |
| 555 | 531 | ams369fg06_power(lcd, FB_BLANK_POWERDOWN); |
| 556 | 532 | backlight_device_unregister(lcd->bd); |
| @@ -560,44 +536,26 @@ static int ams369fg06_remove(struct spi_device *spi) · 3 unmodified lines | ||
| 560 | 536 | } |
| 561 | 537 | |
| 562 | 538 | #if defined(CONFIG_PM) |
| 563 | −static unsigned int before_power; | |
| 564 | − | |
| 565 | 539 | static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg) |
| 566 | 540 | { |
| 567 | − int ret = 0; | |
| 568 | − struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | |
| 541 | + struct ams369fg06 *lcd = spi_get_drvdata(spi); | |
| 569 | 542 | |
| 570 | 543 | dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); |
| 571 | 544 | |
| 572 | − before_power = lcd->power; | |
| 573 | − | |
| 574 | 545 | /* |
| 575 | 546 | * when lcd panel is suspend, lcd panel becomes off |
| 576 | 547 | * regardless of status. |
| 577 | 548 | */ |
| 578 | − ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN); | |
| 579 | − | |
| 580 | − return ret; | |
| 549 | + return ams369fg06_power(lcd, FB_BLANK_POWERDOWN); | |
| 581 | 550 | } |
| 582 | 551 | |
| 583 | 552 | static int ams369fg06_resume(struct spi_device *spi) |
| 584 | 553 | { |
| 585 | − int ret = 0; | |
| 586 | − struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | |
| 554 | + struct ams369fg06 *lcd = spi_get_drvdata(spi); | |
| 587 | 555 | |
| 588 | − /* | |
| 589 | − * after suspended, if lcd panel status is FB_BLANK_UNBLANK | |
| 590 | − * (at that time, before_power is FB_BLANK_UNBLANK) then | |
| 591 | − * it changes that status to FB_BLANK_POWERDOWN to get lcd on. | |
| 592 | − */ | |
| 593 | − if (before_power == FB_BLANK_UNBLANK) | |
| 594 | − lcd->power = FB_BLANK_POWERDOWN; | |
| 595 | − | |
| 596 | − dev_dbg(&spi->dev, "before_power = %d\n", before_power); | |
| 556 | + lcd->power = FB_BLANK_POWERDOWN; | |
| 597 | 557 | |
| 598 | − ret = ams369fg06_power(lcd, before_power); | |
| 599 | − | |
| 600 | − return ret; | |
| 558 | + return ams369fg06_power(lcd, FB_BLANK_UNBLANK); | |
| 601 | 559 | } |
| 602 | 560 | #else |
| 603 | 561 | #define ams369fg06_suspend NULL |
| @@ -606,7 +564,7 @@ static int ams369fg06_resume(struct spi_device *spi) · 2 unmodified lines | ||
| 606 | 564 | |
| 607 | 565 | static void ams369fg06_shutdown(struct spi_device *spi) |
| 608 | 566 | { |
| 609 | − struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | |
| 567 | + struct ams369fg06 *lcd = spi_get_drvdata(spi); | |
| 610 | 568 | |
| 611 | 569 | ams369fg06_power(lcd, FB_BLANK_POWERDOWN); |
| 612 | 570 | } |
| @@ -0,0 +1,380 @@ | ||
| 1 | +/* | |
| 2 | + * AS3711 PMIC backlight driver, using DCDC Step Up Converters | |
| 3 | + * | |
| 4 | + * Copyright (C) 2012 Renesas Electronics Corporation | |
| 5 | + * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify | |
| 8 | + * it under the terms of the version 2 of the GNU General Public License as | |
| 9 | + * published by the Free Software Foundation | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/backlight.h> | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/err.h> | |
| 16 | +#include <linux/fb.h> | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/mfd/as3711.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/platform_device.h> | |
| 21 | +#include <linux/regmap.h> | |
| 22 | +#include <linux/slab.h> | |
| 23 | + | |
| 24 | +enum as3711_bl_type { | |
| 25 | + AS3711_BL_SU1, | |
| 26 | + AS3711_BL_SU2, | |
| 27 | +}; | |
| 28 | + | |
| 29 | +struct as3711_bl_data { | |
| 30 | + bool powered; | |
| 31 | + const char *fb_name; | |
| 32 | + struct device *fb_dev; | |
| 33 | + enum as3711_bl_type type; | |
| 34 | + int brightness; | |
| 35 | + struct backlight_device *bl; | |
| 36 | +}; | |
| 37 | + | |
| 38 | +struct as3711_bl_supply { | |
| 39 | + struct as3711_bl_data su1; | |
| 40 | + struct as3711_bl_data su2; | |
| 41 | + const struct as3711_bl_pdata *pdata; | |
| 42 | + struct as3711 *as3711; | |
| 43 | +}; | |
| 44 | + | |
| 45 | +static struct as3711_bl_supply *to_supply(struct as3711_bl_data *su) | |
| 46 | +{ | |
| 47 | + switch (su->type) { | |
| 48 | + case AS3711_BL_SU1: | |
| 49 | + return container_of(su, struct as3711_bl_supply, su1); | |
| 50 | + case AS3711_BL_SU2: | |
| 51 | + return container_of(su, struct as3711_bl_supply, su2); | |
| 52 | + } | |
| 53 | + return NULL; | |
| 54 | +} | |
| 55 | + | |
| 56 | +static int as3711_set_brightness_auto_i(struct as3711_bl_data *data, | |
| 57 | + unsigned int brightness) | |
| 58 | +{ | |
| 59 | + struct as3711_bl_supply *supply = to_supply(data); | |
| 60 | + struct as3711 *as3711 = supply->as3711; | |
| 61 | + const struct as3711_bl_pdata *pdata = supply->pdata; | |
| 62 | + int ret = 0; | |
| 63 | + | |
| 64 | + /* Only all equal current values are supported */ | |
| 65 | + if (pdata->su2_auto_curr1) | |
| 66 | + ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE, | |
| 67 | + brightness); | |
| 68 | + if (!ret && pdata->su2_auto_curr2) | |
| 69 | + ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE, | |
| 70 | + brightness); | |
| 71 | + if (!ret && pdata->su2_auto_curr3) | |
| 72 | + ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE, | |
| 73 | + brightness); | |
| 74 | + | |
| 75 | + return ret; | |
| 76 | +} | |
| 77 | + | |
| 78 | +static int as3711_set_brightness_v(struct as3711 *as3711, | |
| 79 | + unsigned int brightness, | |
| 80 | + unsigned int reg) | |
| 81 | +{ | |
| 82 | + if (brightness > 31) | |
| 83 | + return -EINVAL; | |
| 84 | + | |
| 85 | + return regmap_update_bits(as3711->regmap, reg, 0xf0, | |
| 86 | + brightness << 4); | |
| 87 | +} | |
| 88 | + | |
| 89 | +static int as3711_bl_su2_reset(struct as3711_bl_supply *supply) | |
| 90 | +{ | |
| 91 | + struct as3711 *as3711 = supply->as3711; | |
| 92 | + int ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_5, | |
| 93 | + 3, supply->pdata->su2_fbprot); | |
| 94 | + if (!ret) | |
| 95 | + ret = regmap_update_bits(as3711->regmap, | |
| 96 | + AS3711_STEPUP_CONTROL_2, 1, 0); | |
| 97 | + if (!ret) | |
| 98 | + ret = regmap_update_bits(as3711->regmap, | |
| 99 | + AS3711_STEPUP_CONTROL_2, 1, 1); | |
| 100 | + return ret; | |
| 101 | +} | |
| 102 | + | |
| 103 | +/* | |
| 104 | + * Someone with less fragile or less expensive hardware could try to simplify | |
| 105 | + * the brightness adjustment procedure. | |
| 106 | + */ | |
| 107 | +static int as3711_bl_update_status(struct backlight_device *bl) | |
| 108 | +{ | |
| 109 | + struct as3711_bl_data *data = bl_get_data(bl); | |
| 110 | + struct as3711_bl_supply *supply = to_supply(data); | |
| 111 | + struct as3711 *as3711 = supply->as3711; | |
| 112 | + int brightness = bl->props.brightness; | |
| 113 | + int ret = 0; | |
| 114 | + | |
| 115 | + dev_dbg(&bl->dev, "%s(): brightness %u, pwr %x, blank %x, state %x\n", | |
| 116 | + __func__, bl->props.brightness, bl->props.power, | |
| 117 | + bl->props.fb_blank, bl->props.state); | |
| 118 | + | |
| 119 | + if (bl->props.power != FB_BLANK_UNBLANK || | |
| 120 | + bl->props.fb_blank != FB_BLANK_UNBLANK || | |
| 121 | + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | |
| 122 | + brightness = 0; | |
| 123 | + | |
| 124 | + if (data->type == AS3711_BL_SU1) { | |
| 125 | + ret = as3711_set_brightness_v(as3711, brightness, | |
| 126 | + AS3711_STEPUP_CONTROL_1); | |
| 127 | + } else { | |
| 128 | + const struct as3711_bl_pdata *pdata = supply->pdata; | |
| 129 | + | |
| 130 | + switch (pdata->su2_feedback) { | |
| 131 | + case AS3711_SU2_VOLTAGE: | |
| 132 | + ret = as3711_set_brightness_v(as3711, brightness, | |
| 133 | + AS3711_STEPUP_CONTROL_2); | |
| 134 | + break; | |
| 135 | + case AS3711_SU2_CURR_AUTO: | |
| 136 | + ret = as3711_set_brightness_auto_i(data, brightness / 4); | |
| 137 | + if (ret < 0) | |
| 138 | + return ret; | |
| 139 | + if (brightness) { | |
| 140 | + ret = as3711_bl_su2_reset(supply); | |
| 141 | + if (ret < 0) | |
| 142 | + return ret; | |
| 143 | + udelay(500); | |
| 144 | + ret = as3711_set_brightness_auto_i(data, brightness); | |
| 145 | + } else { | |
| 146 | + ret = regmap_update_bits(as3711->regmap, | |
| 147 | + AS3711_STEPUP_CONTROL_2, 1, 0); | |
| 148 | + } | |
| 149 | + break; | |
| 150 | + /* Manual one current feedback pin below */ | |
| 151 | + case AS3711_SU2_CURR1: | |
| 152 | + ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE, | |
| 153 | + brightness); | |
| 154 | + break; | |
| 155 | + case AS3711_SU2_CURR2: | |
| 156 | + ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE, | |
| 157 | + brightness); | |
| 158 | + break; | |
| 159 | + case AS3711_SU2_CURR3: | |
| 160 | + ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE, | |
| 161 | + brightness); | |
| 162 | + break; | |
| 163 | + default: | |
| 164 | + ret = -EINVAL; | |
| 165 | + } | |
| 166 | + } | |
| 167 | + if (!ret) | |
| 168 | + data->brightness = brightness; | |
| 169 | + | |
| 170 | + return ret; | |
| 171 | +} | |
| 172 | + | |
| 173 | +static int as3711_bl_get_brightness(struct backlight_device *bl) | |
| 174 | +{ | |
| 175 | + struct as3711_bl_data *data = bl_get_data(bl); | |
| 176 | + | |
| 177 | + return data->brightness; | |
| 178 | +} | |
| 179 | + | |
| 180 | +static const struct backlight_ops as3711_bl_ops = { | |
| 181 | + .update_status = as3711_bl_update_status, | |
| 182 | + .get_brightness = as3711_bl_get_brightness, | |
| 183 | +}; | |
| 184 | + | |
| 185 | +static int as3711_bl_init_su2(struct as3711_bl_supply *supply) | |
| 186 | +{ | |
| 187 | + struct as3711 *as3711 = supply->as3711; | |
| 188 | + const struct as3711_bl_pdata *pdata = supply->pdata; | |
| 189 | + u8 ctl = 0; | |
| 190 | + int ret; | |
| 191 | + | |
| 192 | + dev_dbg(as3711->dev, "%s(): use %u\n", __func__, pdata->su2_feedback); | |
| 193 | + | |
| 194 | + /* Turn SU2 off */ | |
| 195 | + ret = regmap_write(as3711->regmap, AS3711_STEPUP_CONTROL_2, 0); | |
| 196 | + if (ret < 0) | |
| 197 | + return ret; | |
| 198 | + | |
| 199 | + switch (pdata->su2_feedback) { | |
| 200 | + case AS3711_SU2_VOLTAGE: | |
| 201 | + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 0); | |
| 202 | + break; | |
| 203 | + case AS3711_SU2_CURR1: | |
| 204 | + ctl = 1; | |
| 205 | + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 1); | |
| 206 | + break; | |
| 207 | + case AS3711_SU2_CURR2: | |
| 208 | + ctl = 4; | |
| 209 | + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 2); | |
| 210 | + break; | |
| 211 | + case AS3711_SU2_CURR3: | |
| 212 | + ctl = 0x10; | |
| 213 | + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 3); | |
| 214 | + break; | |
| 215 | + case AS3711_SU2_CURR_AUTO: | |
| 216 | + if (pdata->su2_auto_curr1) | |
| 217 | + ctl = 2; | |
| 218 | + if (pdata->su2_auto_curr2) | |
| 219 | + ctl |= 8; | |
| 220 | + if (pdata->su2_auto_curr3) | |
| 221 | + ctl |= 0x20; | |
| 222 | + ret = 0; | |
| 223 | + break; | |
| 224 | + default: | |
| 225 | + return -EINVAL; | |
| 226 | + } | |
| 227 | + | |
| 228 | + if (!ret) | |
| 229 | + ret = regmap_write(as3711->regmap, AS3711_CURR_CONTROL, ctl); | |
| 230 | + | |
| 231 | + return ret; | |
| 232 | +} | |
| 233 | + | |
| 234 | +static int as3711_bl_register(struct platform_device *pdev, | |
| 235 | + unsigned int max_brightness, struct as3711_bl_data *su) | |
| 236 | +{ | |
| 237 | + struct backlight_properties props = {.type = BACKLIGHT_RAW,}; | |
| 238 | + struct backlight_device *bl; | |
| 239 | + | |
| 240 | + /* max tuning I = 31uA for voltage- and 38250uA for current-feedback */ | |
| 241 | + props.max_brightness = max_brightness; | |
| 242 | + | |
| 243 | + bl = backlight_device_register(su->type == AS3711_BL_SU1 ? | |
| 244 | + "as3711-su1" : "as3711-su2", | |
| 245 | + &pdev->dev, su, | |
| 246 | + &as3711_bl_ops, &props); | |
| 247 | + if (IS_ERR(bl)) { | |
| 248 | + dev_err(&pdev->dev, "failed to register backlight\n"); | |
| 249 | + return PTR_ERR(bl); | |
| 250 | + } | |
| 251 | + | |
| 252 | + bl->props.brightness = props.max_brightness; | |
| 253 | + | |
| 254 | + backlight_update_status(bl); | |
| 255 | + | |
| 256 | + su->bl = bl; | |
| 257 | + | |
| 258 | + return 0; | |
| 259 | +} | |
| 260 | + | |
| 261 | +static int as3711_backlight_probe(struct platform_device *pdev) | |
| 262 | +{ | |
| 263 | + struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev); | |
| 264 | + struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); | |
| 265 | + struct as3711_bl_supply *supply; | |
| 266 | + struct as3711_bl_data *su; | |
| 267 | + unsigned int max_brightness; | |
| 268 | + int ret; | |
| 269 | + | |
| 270 | + if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) { | |
| 271 | + dev_err(&pdev->dev, "No platform data, exiting...\n"); | |
| 272 | + return -ENODEV; | |
| 273 | + } | |
| 274 | + | |
| 275 | + /* | |
| 276 | + * Due to possible hardware damage I chose to block all modes, | |
| 277 | + * unsupported on my hardware. Anyone, wishing to use any of those modes | |
| 278 | + * will have to first review the code, then activate and test it. | |
| 279 | + */ | |
| 280 | + if (pdata->su1_fb || | |
| 281 | + pdata->su2_fbprot != AS3711_SU2_GPIO4 || | |
| 282 | + pdata->su2_feedback != AS3711_SU2_CURR_AUTO) { | |
| 283 | + dev_warn(&pdev->dev, | |
| 284 | + "Attention! An untested mode has been chosen!\n" | |
| 285 | + "Please, review the code, enable, test, and report success:-)\n"); | |
| 286 | + return -EINVAL; | |
| 287 | + } | |
| 288 | + | |
| 289 | + supply = devm_kzalloc(&pdev->dev, sizeof(*supply), GFP_KERNEL); | |
| 290 | + if (!supply) | |
| 291 | + return -ENOMEM; | |
| 292 | + | |
| 293 | + supply->as3711 = as3711; | |
| 294 | + supply->pdata = pdata; | |
| 295 | + | |
| 296 | + if (pdata->su1_fb) { | |
| 297 | + su = &supply->su1; | |
| 298 | + su->fb_name = pdata->su1_fb; | |
| 299 | + su->type = AS3711_BL_SU1; | |
| 300 | + | |
| 301 | + max_brightness = min(pdata->su1_max_uA, 31); | |
| 302 | + ret = as3711_bl_register(pdev, max_brightness, su); | |
| 303 | + if (ret < 0) | |
| 304 | + return ret; | |
| 305 | + } | |
| 306 | + | |
| 307 | + if (pdata->su2_fb) { | |
| 308 | + su = &supply->su2; | |
| 309 | + su->fb_name = pdata->su2_fb; | |
| 310 | + su->type = AS3711_BL_SU2; | |
| 311 | + | |
| 312 | + switch (pdata->su2_fbprot) { | |
| 313 | + case AS3711_SU2_GPIO2: | |
| 314 | + case AS3711_SU2_GPIO3: | |
| 315 | + case AS3711_SU2_GPIO4: | |
| 316 | + case AS3711_SU2_LX_SD4: | |
| 317 | + break; | |
| 318 | + default: | |
| 319 | + ret = -EINVAL; | |
| 320 | + goto esu2; | |
| 321 | + } | |
| 322 | + | |
| 323 | + switch (pdata->su2_feedback) { | |
| 324 | + case AS3711_SU2_VOLTAGE: | |
| 325 | + max_brightness = min(pdata->su2_max_uA, 31); | |
| 326 | + break; | |
| 327 | + case AS3711_SU2_CURR1: | |
| 328 | + case AS3711_SU2_CURR2: | |
| 329 | + case AS3711_SU2_CURR3: | |
| 330 | + case AS3711_SU2_CURR_AUTO: | |
| 331 | + max_brightness = min(pdata->su2_max_uA / 150, 255); | |
| 332 | + break; | |
| 333 | + default: | |
| 334 | + ret = -EINVAL; | |
| 335 | + goto esu2; | |
| 336 | + } | |
| 337 | + | |
| 338 | + ret = as3711_bl_init_su2(supply); | |
| 339 | + if (ret < 0) | |
| 340 | + return ret; | |
| 341 | + | |
| 342 | + ret = as3711_bl_register(pdev, max_brightness, su); | |
| 343 | + if (ret < 0) | |
| 344 | + goto esu2; | |
| 345 | + } | |
| 346 | + | |
| 347 | + platform_set_drvdata(pdev, supply); | |
| 348 | + | |
| 349 | + return 0; | |
| 350 | + | |
| 351 | +esu2: | |
| 352 | + backlight_device_unregister(supply->su1.bl); | |
| 353 | + return ret; | |
| 354 | +} | |
| 355 | + | |
| 356 | +static int as3711_backlight_remove(struct platform_device *pdev) | |
| 357 | +{ | |
| 358 | + struct as3711_bl_supply *supply = platform_get_drvdata(pdev); | |
| 359 | + | |
| 360 | + backlight_device_unregister(supply->su1.bl); | |
| 361 | + backlight_device_unregister(supply->su2.bl); | |
| 362 | + | |
| 363 | + return 0; | |
| 364 | +} | |
| 365 | + | |
| 366 | +static struct platform_driver as3711_backlight_driver = { | |
| 367 | + .driver = { | |
| 368 | + .name = "as3711-backlight", | |
| 369 | + .owner = THIS_MODULE, | |
| 370 | + }, | |
| 371 | + .probe = as3711_backlight_probe, | |
| 372 | + .remove = as3711_backlight_remove, | |
| 373 | +}; | |
| 374 | + | |
| 375 | +module_platform_driver(as3711_backlight_driver); | |
| 376 | + | |
| 377 | +MODULE_DESCRIPTION("Backlight Driver for AS3711 PMICs"); | |
| 378 | +MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de"); | |
| 379 | +MODULE_LICENSE("GPL"); | |
| 380 | +MODULE_ALIAS("platform:as3711-backlight"); | |
| @@ -337,7 +337,7 @@ static void corgi_lcd_power_off(struct corgi_lcd *lcd) · 336 unmodified lines | ||
| 337 | 337 | |
| 338 | 338 | static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) |
| 339 | 339 | { |
| 340 | − struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | |
| 340 | + struct corgi_lcd *lcd = lcd_get_data(ld); | |
| 341 | 341 | int mode = CORGI_LCD_MODE_QVGA; |
| 342 | 342 | |
| 343 | 343 | if (m->xres == 640 || m->xres == 480) |
| @@ -364,7 +364,7 @@ static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) · 20 unmodified lines | ||
| 364 | 364 | |
| 365 | 365 | static int corgi_lcd_set_power(struct lcd_device *ld, int power) |
| 366 | 366 | { |
| 367 | − struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | |
| 367 | + struct corgi_lcd *lcd = lcd_get_data(ld); | |
| 368 | 368 | |
| 369 | 369 | if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) |
| 370 | 370 | corgi_lcd_power_on(lcd); |
| @@ -378,7 +378,7 @@ static int corgi_lcd_set_power(struct lcd_device *ld, int power) · 7 unmodified lines | ||
| 378 | 378 | |
| 379 | 379 | static int corgi_lcd_get_power(struct lcd_device *ld) |
| 380 | 380 | { |
| 381 | − struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | |
| 381 | + struct corgi_lcd *lcd = lcd_get_data(ld); | |
| 382 | 382 | |
| 383 | 383 | return lcd->power; |
| 384 | 384 | } |
| @@ -391,7 +391,7 @@ static struct lcd_ops corgi_lcd_ops = { · 6 unmodified lines | ||
| 391 | 391 | |
| 392 | 392 | static int corgi_bl_get_intensity(struct backlight_device *bd) |
| 393 | 393 | { |
| 394 | − struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); | |
| 394 | + struct corgi_lcd *lcd = bl_get_data(bd); | |
| 395 | 395 | |
| 396 | 396 | return lcd->intensity; |
| 397 | 397 | } |
| @@ -423,7 +423,7 @@ static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity) · 25 unmodified lines | ||
| 423 | 423 | |
| 424 | 424 | static int corgi_bl_update_status(struct backlight_device *bd) |
| 425 | 425 | { |
| 426 | − struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); | |
| 426 | + struct corgi_lcd *lcd = bl_get_data(bd); | |
| 427 | 427 | int intensity = bd->props.brightness; |
| 428 | 428 | |
| 429 | 429 | if (bd->props.power != FB_BLANK_UNBLANK) |
| @@ -460,7 +460,7 @@ static const struct backlight_ops corgi_bl_ops = { · 30 unmodified lines | ||
| 460 | 460 | #ifdef CONFIG_PM |
| 461 | 461 | static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state) |
| 462 | 462 | { |
| 463 | − struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | |
| 463 | + struct corgi_lcd *lcd = spi_get_drvdata(spi); | |
| 464 | 464 | |
| 465 | 465 | corgibl_flags |= CORGIBL_SUSPENDED; |
| 466 | 466 | corgi_bl_set_intensity(lcd, 0); |
| @@ -470,7 +470,7 @@ static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state) · 3 unmodified lines | ||
| 470 | 470 | |
| 471 | 471 | static int corgi_lcd_resume(struct spi_device *spi) |
| 472 | 472 | { |
| 473 | − struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | |
| 473 | + struct corgi_lcd *lcd = spi_get_drvdata(spi); | |
| 474 | 474 | |
| 475 | 475 | corgibl_flags &= ~CORGIBL_SUSPENDED; |
| 476 | 476 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); |
| @@ -577,7 +577,7 @@ static int corgi_lcd_probe(struct spi_device *spi) · 100 unmodified lines | ||
| 577 | 577 | |
| 578 | 578 | lcd->kick_battery = pdata->kick_battery; |
| 579 | 579 | |
| 580 | − dev_set_drvdata(&spi->dev, lcd); | |
| 580 | + spi_set_drvdata(spi, lcd); | |
| 581 | 581 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); |
| 582 | 582 | backlight_update_status(lcd->bl_dev); |
| 583 | 583 | |
| @@ -594,7 +594,7 @@ err_unregister_lcd: · 10 unmodified lines | ||
| 594 | 594 | |
| 595 | 595 | static int corgi_lcd_remove(struct spi_device *spi) |
| 596 | 596 | { |
| 597 | − struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | |
| 597 | + struct corgi_lcd *lcd = spi_get_drvdata(spi); | |
| 598 | 598 | |
| 599 | 599 | lcd->bl_dev->props.power = FB_BLANK_UNBLANK; |
| 600 | 600 | lcd->bl_dev->props.brightness = 0; |
| @@ -0,0 +1,497 @@ | ||
| 1 | +/* | |
| 2 | + * Driver for the Himax HX-8357 LCD Controller | |
| 3 | + * | |
| 4 | + * Copyright 2012 Free Electrons | |
| 5 | + * | |
| 6 | + * Licensed under the GPLv2 or later. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/delay.h> | |
| 10 | +#include <linux/lcd.h> | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/of.h> | |
| 13 | +#include <linux/of_device.h> | |
| 14 | +#include <linux/of_gpio.h> | |
| 15 | +#include <linux/spi/spi.h> | |
| 16 | + | |
| 17 | +#define HX8357_NUM_IM_PINS 3 | |
| 18 | + | |
| 19 | +#define HX8357_SWRESET 0x01 | |
| 20 | +#define HX8357_GET_RED_CHANNEL 0x06 | |
| 21 | +#define HX8357_GET_GREEN_CHANNEL 0x07 | |
| 22 | +#define HX8357_GET_BLUE_CHANNEL 0x08 | |
| 23 | +#define HX8357_GET_POWER_MODE 0x0a | |
| 24 | +#define HX8357_GET_MADCTL 0x0b | |
| 25 | +#define HX8357_GET_PIXEL_FORMAT 0x0c | |
| 26 | +#define HX8357_GET_DISPLAY_MODE 0x0d | |
| 27 | +#define HX8357_GET_SIGNAL_MODE 0x0e | |
| 28 | +#define HX8357_GET_DIAGNOSTIC_RESULT 0x0f | |
| 29 | +#define HX8357_ENTER_SLEEP_MODE 0x10 | |
| 30 | +#define HX8357_EXIT_SLEEP_MODE 0x11 | |
| 31 | +#define HX8357_ENTER_PARTIAL_MODE 0x12 | |
| 32 | +#define HX8357_ENTER_NORMAL_MODE 0x13 | |
| 33 | +#define HX8357_EXIT_INVERSION_MODE 0x20 | |
| 34 | +#define HX8357_ENTER_INVERSION_MODE 0x21 | |
| 35 | +#define HX8357_SET_DISPLAY_OFF 0x28 | |
| 36 | +#define HX8357_SET_DISPLAY_ON 0x29 | |
| 37 | +#define HX8357_SET_COLUMN_ADDRESS 0x2a | |
| 38 | +#define HX8357_SET_PAGE_ADDRESS 0x2b | |
| 39 | +#define HX8357_WRITE_MEMORY_START 0x2c | |
| 40 | +#define HX8357_READ_MEMORY_START 0x2e | |
| 41 | +#define HX8357_SET_PARTIAL_AREA 0x30 | |
| 42 | +#define HX8357_SET_SCROLL_AREA 0x33 | |
| 43 | +#define HX8357_SET_TEAR_OFF 0x34 | |
| 44 | +#define HX8357_SET_TEAR_ON 0x35 | |
| 45 | +#define HX8357_SET_ADDRESS_MODE 0x36 | |
| 46 | +#define HX8357_SET_SCROLL_START 0x37 | |
| 47 | +#define HX8357_EXIT_IDLE_MODE 0x38 | |
| 48 | +#define HX8357_ENTER_IDLE_MODE 0x39 | |
| 49 | +#define HX8357_SET_PIXEL_FORMAT 0x3a | |
| 50 | +#define HX8357_SET_PIXEL_FORMAT_DBI_3BIT (0x1) | |
| 51 | +#define HX8357_SET_PIXEL_FORMAT_DBI_16BIT (0x5) | |
| 52 | +#define HX8357_SET_PIXEL_FORMAT_DBI_18BIT (0x6) | |
| 53 | +#define HX8357_SET_PIXEL_FORMAT_DPI_3BIT (0x1 << 4) | |
| 54 | +#define HX8357_SET_PIXEL_FORMAT_DPI_16BIT (0x5 << 4) | |
| 55 | +#define HX8357_SET_PIXEL_FORMAT_DPI_18BIT (0x6 << 4) | |
| 56 | +#define HX8357_WRITE_MEMORY_CONTINUE 0x3c | |
| 57 | +#define HX8357_READ_MEMORY_CONTINUE 0x3e | |
| 58 | +#define HX8357_SET_TEAR_SCAN_LINES 0x44 | |
| 59 | +#define HX8357_GET_SCAN_LINES 0x45 | |
| 60 | +#define HX8357_READ_DDB_START 0xa1 | |
| 61 | +#define HX8357_SET_DISPLAY_MODE 0xb4 | |
| 62 | +#define HX8357_SET_DISPLAY_MODE_RGB_THROUGH (0x3) | |
| 63 | +#define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE (1 << 4) | |
| 64 | +#define HX8357_SET_PANEL_DRIVING 0xc0 | |
| 65 | +#define HX8357_SET_DISPLAY_FRAME 0xc5 | |
| 66 | +#define HX8357_SET_RGB 0xc6 | |
| 67 | +#define HX8357_SET_RGB_ENABLE_HIGH (1 << 1) | |
| 68 | +#define HX8357_SET_GAMMA 0xc8 | |
| 69 | +#define HX8357_SET_POWER 0xd0 | |
| 70 | +#define HX8357_SET_VCOM 0xd1 | |
| 71 | +#define HX8357_SET_POWER_NORMAL 0xd2 | |
| 72 | +#define HX8357_SET_PANEL_RELATED 0xe9 | |
| 73 | + | |
| 74 | +struct hx8357_data { | |
| 75 | + unsigned im_pins[HX8357_NUM_IM_PINS]; | |
| 76 | + unsigned reset; | |
| 77 | + struct spi_device *spi; | |
| 78 | + int state; | |
| 79 | +}; | |
| 80 | + | |
| 81 | +static u8 hx8357_seq_power[] = { | |
| 82 | + HX8357_SET_POWER, 0x44, 0x41, 0x06, | |
| 83 | +}; | |
| 84 | + | |
| 85 | +static u8 hx8357_seq_vcom[] = { | |
| 86 | + HX8357_SET_VCOM, 0x40, 0x10, | |
| 87 | +}; | |
| 88 | + | |
| 89 | +static u8 hx8357_seq_power_normal[] = { | |
| 90 | + HX8357_SET_POWER_NORMAL, 0x05, 0x12, | |
| 91 | +}; | |
| 92 | + | |
| 93 | +static u8 hx8357_seq_panel_driving[] = { | |
| 94 | + HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11, | |
| 95 | +}; | |
| 96 | + | |
| 97 | +static u8 hx8357_seq_display_frame[] = { | |
| 98 | + HX8357_SET_DISPLAY_FRAME, 0x0c, | |
| 99 | +}; | |
| 100 | + | |
| 101 | +static u8 hx8357_seq_panel_related[] = { | |
| 102 | + HX8357_SET_PANEL_RELATED, 0x01, | |
| 103 | +}; | |
| 104 | + | |
| 105 | +static u8 hx8357_seq_undefined1[] = { | |
| 106 | + 0xea, 0x03, 0x00, 0x00, | |
| 107 | +}; | |
| 108 | + | |
| 109 | +static u8 hx8357_seq_undefined2[] = { | |
| 110 | + 0xeb, 0x40, 0x54, 0x26, 0xdb, | |
| 111 | +}; | |
| 112 | + | |
| 113 | +static u8 hx8357_seq_gamma[] = { | |
| 114 | + HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00, | |
| 115 | + 0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00, | |
| 116 | +}; | |
| 117 | + | |
| 118 | +static u8 hx8357_seq_address_mode[] = { | |
| 119 | + HX8357_SET_ADDRESS_MODE, 0xc0, | |
| 120 | +}; | |
| 121 | + | |
| 122 | +static u8 hx8357_seq_pixel_format[] = { | |
| 123 | + HX8357_SET_PIXEL_FORMAT, | |
| 124 | + HX8357_SET_PIXEL_FORMAT_DPI_18BIT | | |
| 125 | + HX8357_SET_PIXEL_FORMAT_DBI_18BIT, | |
| 126 | +}; | |
| 127 | + | |
| 128 | +static u8 hx8357_seq_column_address[] = { | |
| 129 | + HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f, | |
| 130 | +}; | |
| 131 | + | |
| 132 | +static u8 hx8357_seq_page_address[] = { | |
| 133 | + HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf, | |
| 134 | +}; | |
| 135 | + | |
| 136 | +static u8 hx8357_seq_rgb[] = { | |
| 137 | + HX8357_SET_RGB, 0x02, | |
| 138 | +}; | |
| 139 | + | |
| 140 | +static u8 hx8357_seq_display_mode[] = { | |
| 141 | + HX8357_SET_DISPLAY_MODE, | |
| 142 | + HX8357_SET_DISPLAY_MODE_RGB_THROUGH | | |
| 143 | + HX8357_SET_DISPLAY_MODE_RGB_INTERFACE, | |
| 144 | +}; | |
| 145 | + | |
| 146 | +static int hx8357_spi_write_then_read(struct lcd_device *lcdev, | |
| 147 | + u8 *txbuf, u16 txlen, | |
| 148 | + u8 *rxbuf, u16 rxlen) | |
| 149 | +{ | |
| 150 | + struct hx8357_data *lcd = lcd_get_data(lcdev); | |
| 151 | + struct spi_message msg; | |
| 152 | + struct spi_transfer xfer[2]; | |
| 153 | + u16 *local_txbuf = NULL; | |
| 154 | + int ret = 0; | |
| 155 | + | |
| 156 | + memset(xfer, 0, sizeof(xfer)); | |
| 157 | + spi_message_init(&msg); | |
| 158 | + | |
| 159 | + if (txlen) { | |
| 160 | + int i; | |
| 161 | + | |
| 162 | + local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL); | |
| 163 | + | |
| 164 | + if (!local_txbuf) | |
| 165 | + return -ENOMEM; | |
| 166 | + | |
| 167 | + for (i = 0; i < txlen; i++) { | |
| 168 | + local_txbuf[i] = txbuf[i]; | |
| 169 | + if (i > 0) | |
| 170 | + local_txbuf[i] |= 1 << 8; | |
| 171 | + } | |
| 172 | + | |
| 173 | + xfer[0].len = 2 * txlen; | |
| 174 | + xfer[0].bits_per_word = 9; | |
| 175 | + xfer[0].tx_buf = local_txbuf; | |
| 176 | + spi_message_add_tail(&xfer[0], &msg); | |
| 177 | + } | |
| 178 | + | |
| 179 | + if (rxlen) { | |
| 180 | + xfer[1].len = rxlen; | |
| 181 | + xfer[1].bits_per_word = 8; | |
| 182 | + xfer[1].rx_buf = rxbuf; | |
| 183 | + spi_message_add_tail(&xfer[1], &msg); | |
| 184 | + } | |
| 185 | + | |
| 186 | + ret = spi_sync(lcd->spi, &msg); | |
| 187 | + if (ret < 0) | |
| 188 | + dev_err(&lcdev->dev, "Couldn't send SPI data\n"); | |
| 189 | + | |
| 190 | + if (txlen) | |
| 191 | + kfree(local_txbuf); | |
| 192 | + | |
| 193 | + return ret; | |
| 194 | +} | |
| 195 | + | |
| 196 | +static inline int hx8357_spi_write_array(struct lcd_device *lcdev, | |
| 197 | + u8 *value, u8 len) | |
| 198 | +{ | |
| 199 | + return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0); | |
| 200 | +} | |
| 201 | + | |
| 202 | +static inline int hx8357_spi_write_byte(struct lcd_device *lcdev, | |
| 203 | + u8 value) | |
| 204 | +{ | |
| 205 | + return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0); | |
| 206 | +} | |
| 207 | + | |
| 208 | +static int hx8357_enter_standby(struct lcd_device *lcdev) | |
| 209 | +{ | |
| 210 | + int ret; | |
| 211 | + | |
| 212 | + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF); | |
| 213 | + if (ret < 0) | |
| 214 | + return ret; | |
| 215 | + | |
| 216 | + usleep_range(10000, 12000); | |
| 217 | + | |
| 218 | + ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE); | |
| 219 | + if (ret < 0) | |
| 220 | + return ret; | |
| 221 | + | |
| 222 | + msleep(120); | |
| 223 | + | |
| 224 | + return 0; | |
| 225 | +} | |
| 226 | + | |
| 227 | +static int hx8357_exit_standby(struct lcd_device *lcdev) | |
| 228 | +{ | |
| 229 | + int ret; | |
| 230 | + | |
| 231 | + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); | |
| 232 | + if (ret < 0) | |
| 233 | + return ret; | |
| 234 | + | |
| 235 | + msleep(120); | |
| 236 | + | |
| 237 | + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); | |
| 238 | + if (ret < 0) | |
| 239 | + return ret; | |
| 240 | + | |
| 241 | + return 0; | |
| 242 | +} | |
| 243 | + | |
| 244 | +static int hx8357_lcd_init(struct lcd_device *lcdev) | |
| 245 | +{ | |
| 246 | + struct hx8357_data *lcd = lcd_get_data(lcdev); | |
| 247 | + int ret; | |
| 248 | + | |
| 249 | + /* | |
| 250 | + * Set the interface selection pins to SPI mode, with three | |
| 251 | + * wires | |
| 252 | + */ | |
| 253 | + gpio_set_value_cansleep(lcd->im_pins[0], 1); | |
| 254 | + gpio_set_value_cansleep(lcd->im_pins[1], 0); | |
| 255 | + gpio_set_value_cansleep(lcd->im_pins[2], 1); | |
| 256 | + | |
| 257 | + /* Reset the screen */ | |
| 258 | + gpio_set_value(lcd->reset, 1); | |
| 259 | + usleep_range(10000, 12000); | |
| 260 | + gpio_set_value(lcd->reset, 0); | |
| 261 | + usleep_range(10000, 12000); | |
| 262 | + gpio_set_value(lcd->reset, 1); | |
| 263 | + msleep(120); | |
| 264 | + | |
| 265 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_power, | |
| 266 | + ARRAY_SIZE(hx8357_seq_power)); | |
| 267 | + if (ret < 0) | |
| 268 | + return ret; | |
| 269 | + | |
| 270 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom, | |
| 271 | + ARRAY_SIZE(hx8357_seq_vcom)); | |
| 272 | + if (ret < 0) | |
| 273 | + return ret; | |
| 274 | + | |
| 275 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal, | |
| 276 | + ARRAY_SIZE(hx8357_seq_power_normal)); | |
| 277 | + if (ret < 0) | |
| 278 | + return ret; | |
| 279 | + | |
| 280 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving, | |
| 281 | + ARRAY_SIZE(hx8357_seq_panel_driving)); | |
| 282 | + if (ret < 0) | |
| 283 | + return ret; | |
| 284 | + | |
| 285 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame, | |
| 286 | + ARRAY_SIZE(hx8357_seq_display_frame)); | |
| 287 | + if (ret < 0) | |
| 288 | + return ret; | |
| 289 | + | |
| 290 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related, | |
| 291 | + ARRAY_SIZE(hx8357_seq_panel_related)); | |
| 292 | + if (ret < 0) | |
| 293 | + return ret; | |
| 294 | + | |
| 295 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1, | |
| 296 | + ARRAY_SIZE(hx8357_seq_undefined1)); | |
| 297 | + if (ret < 0) | |
| 298 | + return ret; | |
| 299 | + | |
| 300 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2, | |
| 301 | + ARRAY_SIZE(hx8357_seq_undefined2)); | |
| 302 | + if (ret < 0) | |
| 303 | + return ret; | |
| 304 | + | |
| 305 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma, | |
| 306 | + ARRAY_SIZE(hx8357_seq_gamma)); | |
| 307 | + if (ret < 0) | |
| 308 | + return ret; | |
| 309 | + | |
| 310 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode, | |
| 311 | + ARRAY_SIZE(hx8357_seq_address_mode)); | |
| 312 | + if (ret < 0) | |
| 313 | + return ret; | |
| 314 | + | |
| 315 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format, | |
| 316 | + ARRAY_SIZE(hx8357_seq_pixel_format)); | |
| 317 | + if (ret < 0) | |
| 318 | + return ret; | |
| 319 | + | |
| 320 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address, | |
| 321 | + ARRAY_SIZE(hx8357_seq_column_address)); | |
| 322 | + if (ret < 0) | |
| 323 | + return ret; | |
| 324 | + | |
| 325 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address, | |
| 326 | + ARRAY_SIZE(hx8357_seq_page_address)); | |
| 327 | + if (ret < 0) | |
| 328 | + return ret; | |
| 329 | + | |
| 330 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb, | |
| 331 | + ARRAY_SIZE(hx8357_seq_rgb)); | |
| 332 | + if (ret < 0) | |
| 333 | + return ret; | |
| 334 | + | |
| 335 | + ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode, | |
| 336 | + ARRAY_SIZE(hx8357_seq_display_mode)); | |
| 337 | + if (ret < 0) | |
| 338 | + return ret; | |
| 339 | + | |
| 340 | + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); | |
| 341 | + if (ret < 0) | |
| 342 | + return ret; | |
| 343 | + | |
| 344 | + msleep(120); | |
| 345 | + | |
| 346 | + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); | |
| 347 | + if (ret < 0) | |
| 348 | + return ret; | |
| 349 | + | |
| 350 | + usleep_range(5000, 7000); | |
| 351 | + | |
| 352 | + ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START); | |
| 353 | + if (ret < 0) | |
| 354 | + return ret; | |
| 355 | + | |
| 356 | + return 0; | |
| 357 | +} | |
| 358 | + | |
| 359 | +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) | |
| 360 | + | |
| 361 | +static int hx8357_set_power(struct lcd_device *lcdev, int power) | |
| 362 | +{ | |
| 363 | + struct hx8357_data *lcd = lcd_get_data(lcdev); | |
| 364 | + int ret = 0; | |
| 365 | + | |
| 366 | + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state)) | |
| 367 | + ret = hx8357_exit_standby(lcdev); | |
| 368 | + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state)) | |
| 369 | + ret = hx8357_enter_standby(lcdev); | |
| 370 | + | |
| 371 | + if (ret == 0) | |
| 372 | + lcd->state = power; | |
| 373 | + else | |
| 374 | + dev_warn(&lcdev->dev, "failed to set power mode %d\n", power); | |
| 375 | + | |
| 376 | + return ret; | |
| 377 | +} | |
| 378 | + | |
| 379 | +static int hx8357_get_power(struct lcd_device *lcdev) | |
| 380 | +{ | |
| 381 | + struct hx8357_data *lcd = lcd_get_data(lcdev); | |
| 382 | + | |
| 383 | + return lcd->state; | |
| 384 | +} | |
| 385 | + | |
| 386 | +static struct lcd_ops hx8357_ops = { | |
| 387 | + .set_power = hx8357_set_power, | |
| 388 | + .get_power = hx8357_get_power, | |
| 389 | +}; | |
| 390 | + | |
| 391 | +static int hx8357_probe(struct spi_device *spi) | |
| 392 | +{ | |
| 393 | + struct lcd_device *lcdev; | |
| 394 | + struct hx8357_data *lcd; | |
| 395 | + int i, ret; | |
| 396 | + | |
| 397 | + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); | |
| 398 | + if (!lcd) { | |
| 399 | + dev_err(&spi->dev, "Couldn't allocate lcd internal structure!\n"); | |
| 400 | + return -ENOMEM; | |
| 401 | + } | |
| 402 | + | |
| 403 | + ret = spi_setup(spi); | |
| 404 | + if (ret < 0) { | |
| 405 | + dev_err(&spi->dev, "SPI setup failed.\n"); | |
| 406 | + return ret; | |
| 407 | + } | |
| 408 | + | |
| 409 | + lcd->spi = spi; | |
| 410 | + | |
| 411 | + lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0); | |
| 412 | + if (!gpio_is_valid(lcd->reset)) { | |
| 413 | + dev_err(&spi->dev, "Missing dt property: gpios-reset\n"); | |
| 414 | + return -EINVAL; | |
| 415 | + } | |
| 416 | + | |
| 417 | + ret = devm_gpio_request_one(&spi->dev, lcd->reset, | |
| 418 | + GPIOF_OUT_INIT_HIGH, | |
| 419 | + "hx8357-reset"); | |
| 420 | + if (ret) { | |
| 421 | + dev_err(&spi->dev, | |
| 422 | + "failed to request gpio %d: %d\n", | |
| 423 | + lcd->reset, ret); | |
| 424 | + return -EINVAL; | |
| 425 | + } | |
| 426 | + | |
| 427 | + for (i = 0; i < HX8357_NUM_IM_PINS; i++) { | |
| 428 | + lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node, | |
| 429 | + "im-gpios", i); | |
| 430 | + if (lcd->im_pins[i] == -EPROBE_DEFER) { | |
| 431 | + dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n"); | |
| 432 | + return -EPROBE_DEFER; | |
| 433 | + } | |
| 434 | + if (!gpio_is_valid(lcd->im_pins[i])) { | |
| 435 | + dev_err(&spi->dev, "Missing dt property: im-gpios\n"); | |
| 436 | + return -EINVAL; | |
| 437 | + } | |
| 438 | + | |
| 439 | + ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i], | |
| 440 | + GPIOF_OUT_INIT_LOW, "im_pins"); | |
| 441 | + if (ret) { | |
| 442 | + dev_err(&spi->dev, "failed to request gpio %d: %d\n", | |
| 443 | + lcd->im_pins[i], ret); | |
| 444 | + return -EINVAL; | |
| 445 | + } | |
| 446 | + } | |
| 447 | + | |
| 448 | + lcdev = lcd_device_register("mxsfb", &spi->dev, lcd, &hx8357_ops); | |
| 449 | + if (IS_ERR(lcdev)) { | |
| 450 | + ret = PTR_ERR(lcdev); | |
| 451 | + return ret; | |
| 452 | + } | |
| 453 | + spi_set_drvdata(spi, lcdev); | |
| 454 | + | |
| 455 | + ret = hx8357_lcd_init(lcdev); | |
| 456 | + if (ret) { | |
| 457 | + dev_err(&spi->dev, "Couldn't initialize panel\n"); | |
| 458 | + goto init_error; | |
| 459 | + } | |
| 460 | + | |
| 461 | + dev_info(&spi->dev, "Panel probed\n"); | |
| 462 | + | |
| 463 | + return 0; | |
| 464 | + | |
| 465 | +init_error: | |
| 466 | + lcd_device_unregister(lcdev); | |
| 467 | + return ret; | |
| 468 | +} | |
| 469 | + | |
| 470 | +static int hx8357_remove(struct spi_device *spi) | |
| 471 | +{ | |
| 472 | + struct lcd_device *lcdev = spi_get_drvdata(spi); | |
| 473 | + | |
| 474 | + lcd_device_unregister(lcdev); | |
| 475 | + return 0; | |
| 476 | +} | |
| 477 | + | |
| 478 | +static const struct of_device_id hx8357_dt_ids[] = { | |
| 479 | + { .compatible = "himax,hx8357" }, | |
| 480 | + {}, | |
| 481 | +}; | |
| 482 | +MODULE_DEVICE_TABLE(of, hx8357_dt_ids); | |
| 483 | + | |
| 484 | +static struct spi_driver hx8357_driver = { | |
| 485 | + .probe = hx8357_probe, | |
| 486 | + .remove = hx8357_remove, | |
| 487 | + .driver = { | |
| 488 | + .name = "hx8357", | |
| 489 | + .of_match_table = of_match_ptr(hx8357_dt_ids), | |
| 490 | + }, | |
| 491 | +}; | |
| 492 | + | |
| 493 | +module_spi_driver(hx8357_driver); | |
| 494 | + | |
| 495 | +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | |
| 496 | +MODULE_DESCRIPTION("Himax HX-8357 LCD Driver"); | |
| 497 | +MODULE_LICENSE("GPL"); | |
| @@ -49,7 +49,7 @@ static void l4f00242t03_reset(unsigned int gpio) · 48 unmodified lines | ||
| 49 | 49 | static void l4f00242t03_lcd_init(struct spi_device *spi) |
| 50 | 50 | { |
| 51 | 51 | struct l4f00242t03_pdata *pdata = spi->dev.platform_data; |
| 52 | − struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); | |
| 52 | + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); | |
| 53 | 53 | const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) }; |
| 54 | 54 | |
| 55 | 55 | dev_dbg(&spi->dev, "initializing LCD\n"); |
| @@ -70,7 +70,7 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) · 14 unmodified lines | ||
| 70 | 70 | static void l4f00242t03_lcd_powerdown(struct spi_device *spi) |
| 71 | 71 | { |
| 72 | 72 | struct l4f00242t03_pdata *pdata = spi->dev.platform_data; |
| 73 | − struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); | |
| 73 | + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); | |
| 74 | 74 | |
| 75 | 75 | dev_dbg(&spi->dev, "Powering down LCD\n"); |
| 76 | 76 | |
| @@ -168,7 +168,7 @@ static int l4f00242t03_probe(struct spi_device *spi) · 91 unmodified lines | ||
| 168 | 168 | return -ENOMEM; |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | − dev_set_drvdata(&spi->dev, priv); | |
| 171 | + spi_set_drvdata(spi, priv); | |
| 172 | 172 | spi->bits_per_word = 9; |
| 173 | 173 | spi_setup(spi); |
| 174 | 174 | |
| @@ -190,27 +190,24 @@ static int l4f00242t03_probe(struct spi_device *spi) · 15 unmodified lines | ||
| 190 | 190 | return ret; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | − priv->io_reg = regulator_get(&spi->dev, "vdd"); | |
| 193 | + priv->io_reg = devm_regulator_get(&spi->dev, "vdd"); | |
| 194 | 194 | if (IS_ERR(priv->io_reg)) { |
| 195 | 195 | dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", |
| 196 | 196 | __func__); |
| 197 | 197 | return PTR_ERR(priv->io_reg); |
| 198 | 198 | } |
| 199 | 199 | |
| 200 | − priv->core_reg = regulator_get(&spi->dev, "vcore"); | |
| 200 | + priv->core_reg = devm_regulator_get(&spi->dev, "vcore"); | |
| 201 | 201 | if (IS_ERR(priv->core_reg)) { |
| 202 | − ret = PTR_ERR(priv->core_reg); | |
| 203 | 202 | dev_err(&spi->dev, "%s: Unable to get the core regulator\n", |
| 204 | 203 | __func__); |
| 205 | − goto err1; | |
| 204 | + return PTR_ERR(priv->core_reg); | |
| 206 | 205 | } |
| 207 | 206 | |
| 208 | 207 | priv->ld = lcd_device_register("l4f00242t03", |
| 209 | 208 | &spi->dev, priv, &l4f_ops); |
| 210 | − if (IS_ERR(priv->ld)) { | |
| 211 | − ret = PTR_ERR(priv->ld); | |
| 212 | − goto err2; | |
| 213 | − } | |
| 209 | + if (IS_ERR(priv->ld)) | |
| 210 | + return PTR_ERR(priv->ld); | |
| 214 | 211 | |
| 215 | 212 | /* Init the LCD */ |
| 216 | 213 | l4f00242t03_lcd_init(spi); |
| @@ -220,33 +217,22 @@ static int l4f00242t03_probe(struct spi_device *spi) · 3 unmodified lines | ||
| 220 | 217 | dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n"); |
| 221 | 218 | |
| 222 | 219 | return 0; |
| 223 | − | |
| 224 | −err2: | |
| 225 | − regulator_put(priv->core_reg); | |
| 226 | −err1: | |
| 227 | − regulator_put(priv->io_reg); | |
| 228 | − | |
| 229 | − return ret; | |
| 230 | 220 | } |
| 231 | 221 | |
| 232 | 222 | static int l4f00242t03_remove(struct spi_device *spi) |
| 233 | 223 | { |
| 234 | − struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); | |
| 224 | + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); | |
| 235 | 225 | |
| 236 | 226 | l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); |
| 237 | 227 | lcd_device_unregister(priv->ld); |
| 238 | − | |
| 239 | − dev_set_drvdata(&spi->dev, NULL); | |
| 240 | − | |
| 241 | − regulator_put(priv->io_reg); | |
| 242 | − regulator_put(priv->core_reg); | |
| 228 | + spi_set_drvdata(spi, NULL); | |
| 243 | 229 | |
| 244 | 230 | return 0; |
| 245 | 231 | } |
| 246 | 232 | |
| 247 | 233 | static void l4f00242t03_shutdown(struct spi_device *spi) |
| 248 | 234 | { |
| 249 | − struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); | |
| 235 | + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); | |
| 250 | 236 | |
| 251 | 237 | if (priv) |
| 252 | 238 | l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); |
| @@ -9,29 +9,20 @@ · 8 unmodified lines | ||
| 9 | 9 | * under the terms of the GNU General Public License as published by the |
| 10 | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | 11 | * option) any later version. |
| 12 | − * | |
| 13 | − * This program is distributed in the hope that it will be useful, but | |
| 14 | − * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 16 | − * General Public License for more details. | |
| 17 | − * | |
| 18 | − * You should have received a copy of the GNU General Public License along | |
| 19 | − * with this program; if not, write to the Free Software Foundation, Inc., | |
| 20 | − * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 21 | 12 | */ |
| 22 | 13 | |
| 23 | −#include <linux/wait.h> | |
| 24 | −#include <linux/fb.h> | |
| 14 | +#include <linux/backlight.h> | |
| 25 | 15 | #include <linux/delay.h> |
| 16 | +#include <linux/fb.h> | |
| 26 | 17 | #include <linux/gpio.h> |
| 27 | −#include <linux/spi/spi.h> | |
| 28 | −#include <linux/irq.h> | |
| 29 | 18 | #include <linux/interrupt.h> |
| 19 | +#include <linux/irq.h> | |
| 30 | 20 | #include <linux/kernel.h> |
| 31 | 21 | #include <linux/lcd.h> |
| 32 | −#include <linux/backlight.h> | |
| 33 | 22 | #include <linux/module.h> |
| 34 | 23 | #include <linux/regulator/consumer.h> |
| 24 | +#include <linux/spi/spi.h> | |
| 25 | +#include <linux/wait.h> | |
| 35 | 26 | |
| 36 | 27 | #include "ld9040_gamma.h" |
| 37 | 28 | |
| @@ -43,7 +34,6 @@ · 5 unmodified lines | ||
| 43 | 34 | |
| 44 | 35 | #define MIN_BRIGHTNESS 0 |
| 45 | 36 | #define MAX_BRIGHTNESS 24 |
| 46 | −#define power_is_on(pwr) ((pwr) <= FB_BLANK_NORMAL) | |
| 47 | 37 | |
| 48 | 38 | struct ld9040 { |
| 49 | 39 | struct device *dev; |
| @@ -78,7 +68,7 @@ static void ld9040_regulator_enable(struct ld9040 *lcd) · 28 unmodified lines | ||
| 78 | 68 | |
| 79 | 69 | lcd->enabled = true; |
| 80 | 70 | } |
| 81 | − mdelay(pd->power_on_delay); | |
| 71 | + msleep(pd->power_on_delay); | |
| 82 | 72 | out: |
| 83 | 73 | mutex_unlock(&lcd->lock); |
| 84 | 74 | } |
| @@ -474,8 +464,9 @@ static int ld9040_panel_send_sequence(struct ld9040 *lcd, · 389 unmodified lines | ||
| 474 | 464 | ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); |
| 475 | 465 | if (ret) |
| 476 | 466 | break; |
| 477 | − } else | |
| 478 | − udelay(wbuf[i+1]*1000); | |
| 467 | + } else { | |
| 468 | + msleep(wbuf[i+1]); | |
| 469 | + } | |
| 479 | 470 | i += 2; |
| 480 | 471 | } |
| 481 | 472 | |
| @@ -513,14 +504,9 @@ gamma_err: · 31 unmodified lines | ||
| 513 | 504 | |
| 514 | 505 | static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) |
| 515 | 506 | { |
| 516 | − int ret = 0; | |
| 517 | − | |
| 518 | − ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); | |
| 519 | − | |
| 520 | − return ret; | |
| 507 | + return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); | |
| 521 | 508 | } |
| 522 | 509 | |
| 523 | − | |
| 524 | 510 | static int ld9040_ldi_init(struct ld9040 *lcd) |
| 525 | 511 | { |
| 526 | 512 | int ret, i; |
| @@ -539,7 +525,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd) · 12 unmodified lines | ||
| 539 | 525 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { |
| 540 | 526 | ret = ld9040_panel_send_sequence(lcd, init_seq[i]); |
| 541 | 527 | /* workaround: minimum delay time for transferring CMD */ |
| 542 | − udelay(300); | |
| 528 | + usleep_range(300, 310); | |
| 543 | 529 | if (ret) |
| 544 | 530 | break; |
| 545 | 531 | } |
| @@ -549,11 +535,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd) · 3 unmodified lines | ||
| 549 | 535 | |
| 550 | 536 | static int ld9040_ldi_enable(struct ld9040 *lcd) |
| 551 | 537 | { |
| 552 | − int ret = 0; | |
| 553 | − | |
| 554 | − ret = ld9040_panel_send_sequence(lcd, seq_display_on); | |
| 555 | − | |
| 556 | − return ret; | |
| 538 | + return ld9040_panel_send_sequence(lcd, seq_display_on); | |
| 557 | 539 | } |
| 558 | 540 | |
| 559 | 541 | static int ld9040_ldi_disable(struct ld9040 *lcd) |
| @@ -566,25 +548,27 @@ static int ld9040_ldi_disable(struct ld9040 *lcd) · 6 unmodified lines | ||
| 566 | 548 | return ret; |
| 567 | 549 | } |
| 568 | 550 | |
| 551 | +static int ld9040_power_is_on(int power) | |
| 552 | +{ | |
| 553 | + return power <= FB_BLANK_NORMAL; | |
| 554 | +} | |
| 555 | + | |
| 569 | 556 | static int ld9040_power_on(struct ld9040 *lcd) |
| 570 | 557 | { |
| 571 | 558 | int ret = 0; |
| 572 | − struct lcd_platform_data *pd = NULL; | |
| 559 | + struct lcd_platform_data *pd; | |
| 560 | + | |
| 573 | 561 | pd = lcd->lcd_pd; |
| 574 | − if (!pd) { | |
| 575 | − dev_err(lcd->dev, "platform data is NULL.\n"); | |
| 576 | − return -EFAULT; | |
| 577 | − } | |
| 578 | 562 | |
| 579 | 563 | /* lcd power on */ |
| 580 | 564 | ld9040_regulator_enable(lcd); |
| 581 | 565 | |
| 582 | 566 | if (!pd->reset) { |
| 583 | 567 | dev_err(lcd->dev, "reset is NULL.\n"); |
| 584 | − return -EFAULT; | |
| 568 | + return -EINVAL; | |
| 585 | 569 | } else { |
| 586 | 570 | pd->reset(lcd->ld); |
| 587 | − mdelay(pd->reset_delay); | |
| 571 | + msleep(pd->reset_delay); | |
| 588 | 572 | } |
| 589 | 573 | |
| 590 | 574 | ret = ld9040_ldi_init(lcd); |
| @@ -604,14 +588,10 @@ static int ld9040_power_on(struct ld9040 *lcd) · 13 unmodified lines | ||
| 604 | 588 | |
| 605 | 589 | static int ld9040_power_off(struct ld9040 *lcd) |
| 606 | 590 | { |
| 607 | − int ret = 0; | |
| 608 | − struct lcd_platform_data *pd = NULL; | |
| 591 | + int ret; | |
| 592 | + struct lcd_platform_data *pd; | |
| 609 | 593 | |
| 610 | 594 | pd = lcd->lcd_pd; |
| 611 | − if (!pd) { | |
| 612 | − dev_err(lcd->dev, "platform data is NULL.\n"); | |
| 613 | − return -EFAULT; | |
| 614 | − } | |
| 615 | 595 | |
| 616 | 596 | ret = ld9040_ldi_disable(lcd); |
| 617 | 597 | if (ret) { |
| @@ -619,7 +599,7 @@ static int ld9040_power_off(struct ld9040 *lcd) · 1 unmodified line | ||
| 619 | 599 | return -EIO; |
| 620 | 600 | } |
| 621 | 601 | |
| 622 | − mdelay(pd->power_off_delay); | |
| 602 | + msleep(pd->power_off_delay); | |
| 623 | 603 | |
| 624 | 604 | /* lcd power off */ |
| 625 | 605 | ld9040_regulator_disable(lcd); |
| @@ -631,9 +611,9 @@ static int ld9040_power(struct ld9040 *lcd, int power) · 5 unmodified lines | ||
| 631 | 611 | { |
| 632 | 612 | int ret = 0; |
| 633 | 613 | |
| 634 | − if (power_is_on(power) && !power_is_on(lcd->power)) | |
| 614 | + if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power)) | |
| 635 | 615 | ret = ld9040_power_on(lcd); |
| 636 | − else if (!power_is_on(power) && power_is_on(lcd->power)) | |
| 616 | + else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power)) | |
| 637 | 617 | ret = ld9040_power_off(lcd); |
| 638 | 618 | |
| 639 | 619 | if (!ret) |
| @@ -698,7 +678,6 @@ static const struct backlight_ops ld9040_backlight_ops = { · 58 unmodified lines | ||
| 698 | 678 | .update_status = ld9040_set_brightness, |
| 699 | 679 | }; |
| 700 | 680 | |
| 701 | − | |
| 702 | 681 | static int ld9040_probe(struct spi_device *spi) |
| 703 | 682 | { |
| 704 | 683 | int ret = 0; |
| @@ -726,22 +705,20 @@ static int ld9040_probe(struct spi_device *spi) · 21 unmodified lines | ||
| 726 | 705 | lcd->lcd_pd = spi->dev.platform_data; |
| 727 | 706 | if (!lcd->lcd_pd) { |
| 728 | 707 | dev_err(&spi->dev, "platform data is NULL.\n"); |
| 729 | − return -EFAULT; | |
| 708 | + return -EINVAL; | |
| 730 | 709 | } |
| 731 | 710 | |
| 732 | 711 | mutex_init(&lcd->lock); |
| 733 | 712 | |
| 734 | − ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); | |
| 713 | + ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); | |
| 735 | 714 | if (ret) { |
| 736 | 715 | dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); |
| 737 | 716 | return ret; |
| 738 | 717 | } |
| 739 | 718 | |
| 740 | 719 | ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); |
| 741 | − if (IS_ERR(ld)) { | |
| 742 | − ret = PTR_ERR(ld); | |
| 743 | − goto out_free_regulator; | |
| 744 | − } | |
| 720 | + if (IS_ERR(ld)) | |
| 721 | + return PTR_ERR(ld); | |
| 745 | 722 | |
| 746 | 723 | lcd->ld = ld; |
| 747 | 724 | |
| @@ -772,30 +749,28 @@ static int ld9040_probe(struct spi_device *spi) · 24 unmodified lines | ||
| 772 | 749 | lcd->power = FB_BLANK_POWERDOWN; |
| 773 | 750 | |
| 774 | 751 | ld9040_power(lcd, FB_BLANK_UNBLANK); |
| 775 | − } else | |
| 752 | + } else { | |
| 776 | 753 | lcd->power = FB_BLANK_UNBLANK; |
| 754 | + } | |
| 777 | 755 | |
| 778 | − dev_set_drvdata(&spi->dev, lcd); | |
| 756 | + spi_set_drvdata(spi, lcd); | |
| 779 | 757 | |
| 780 | 758 | dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); |
| 781 | 759 | return 0; |
| 782 | 760 | |
| 783 | 761 | out_unregister_lcd: |
| 784 | 762 | lcd_device_unregister(lcd->ld); |
| 785 | −out_free_regulator: | |
| 786 | − regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | |
| 787 | 763 | |
| 788 | 764 | return ret; |
| 789 | 765 | } |
| 790 | 766 | |
| 791 | 767 | static int ld9040_remove(struct spi_device *spi) |
| 792 | 768 | { |
| 793 | − struct ld9040 *lcd = dev_get_drvdata(&spi->dev); | |
| 769 | + struct ld9040 *lcd = spi_get_drvdata(spi); | |
| 794 | 770 | |
| 795 | 771 | ld9040_power(lcd, FB_BLANK_POWERDOWN); |
| 796 | 772 | backlight_device_unregister(lcd->bd); |
| 797 | 773 | lcd_device_unregister(lcd->ld); |
| 798 | − regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | |
| 799 | 774 | |
| 800 | 775 | return 0; |
| 801 | 776 | } |
| @@ -803,8 +778,7 @@ static int ld9040_remove(struct spi_device *spi) · 1 unmodified line | ||
| 803 | 778 | #if defined(CONFIG_PM) |
| 804 | 779 | static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) |
| 805 | 780 | { |
| 806 | − int ret = 0; | |
| 807 | − struct ld9040 *lcd = dev_get_drvdata(&spi->dev); | |
| 781 | + struct ld9040 *lcd = spi_get_drvdata(spi); | |
| 808 | 782 | |
| 809 | 783 | dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); |
| 810 | 784 | |
| @@ -812,21 +786,16 @@ static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) · 1 unmodified line | ||
| 812 | 786 | * when lcd panel is suspend, lcd panel becomes off |
| 813 | 787 | * regardless of status. |
| 814 | 788 | */ |
| 815 | − ret = ld9040_power(lcd, FB_BLANK_POWERDOWN); | |
| 816 | − | |
| 817 | − return ret; | |
| 789 | + return ld9040_power(lcd, FB_BLANK_POWERDOWN); | |
| 818 | 790 | } |
| 819 | 791 | |
| 820 | 792 | static int ld9040_resume(struct spi_device *spi) |
| 821 | 793 | { |
| 822 | − int ret = 0; | |
| 823 | − struct ld9040 *lcd = dev_get_drvdata(&spi->dev); | |
| 794 | + struct ld9040 *lcd = spi_get_drvdata(spi); | |
| 824 | 795 | |
| 825 | 796 | lcd->power = FB_BLANK_POWERDOWN; |
| 826 | 797 | |
| 827 | − ret = ld9040_power(lcd, FB_BLANK_UNBLANK); | |
| 828 | − | |
| 829 | − return ret; | |
| 798 | + return ld9040_power(lcd, FB_BLANK_UNBLANK); | |
| 830 | 799 | } |
| 831 | 800 | #else |
| 832 | 801 | #define ld9040_suspend NULL |
| @@ -836,7 +805,7 @@ static int ld9040_resume(struct spi_device *spi) · 3 unmodified lines | ||
| 836 | 805 | /* Power down all displays on reboot, poweroff or halt. */ |
| 837 | 806 | static void ld9040_shutdown(struct spi_device *spi) |
| 838 | 807 | { |
| 839 | − struct ld9040 *lcd = dev_get_drvdata(&spi->dev); | |
| 808 | + struct ld9040 *lcd = spi_get_drvdata(spi); | |
| 840 | 809 | |
| 841 | 810 | ld9040_power(lcd, FB_BLANK_POWERDOWN); |
| 842 | 811 | } |
| @@ -320,7 +320,7 @@ static int lm3630_backlight_register(struct lm3630_chip_data *pchip, · 319 unmodified lines | ||
| 320 | 320 | backlight_device_register(name, pchip->dev, pchip, |
| 321 | 321 | &lm3630_bank_a_ops, &props); |
| 322 | 322 | if (IS_ERR(pchip->bled1)) |
| 323 | − return -EIO; | |
| 323 | + return PTR_ERR(pchip->bled1); | |
| 324 | 324 | break; |
| 325 | 325 | case BLED_2: |
| 326 | 326 | props.brightness = pdata->init_brt_led2; |
| @@ -329,7 +329,7 @@ static int lm3630_backlight_register(struct lm3630_chip_data *pchip, · 2 unmodified lines | ||
| 329 | 329 | backlight_device_register(name, pchip->dev, pchip, |
| 330 | 330 | &lm3630_bank_b_ops, &props); |
| 331 | 331 | if (IS_ERR(pchip->bled2)) |
| 332 | − return -EIO; | |
| 332 | + return PTR_ERR(pchip->bled2); | |
| 333 | 333 | break; |
| 334 | 334 | } |
| 335 | 335 | return 0; |
| @@ -350,14 +350,13 @@ static int lm3639_probe(struct i2c_client *client, · 349 unmodified lines | ||
| 350 | 350 | &lm3639_bled_ops, &props); |
| 351 | 351 | if (IS_ERR(pchip->bled)) { |
| 352 | 352 | dev_err(&client->dev, "fail : backlight register\n"); |
| 353 | − ret = -EIO; | |
| 353 | + ret = PTR_ERR(pchip->bled); | |
| 354 | 354 | goto err_out; |
| 355 | 355 | } |
| 356 | 356 | |
| 357 | 357 | ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); |
| 358 | 358 | if (ret < 0) { |
| 359 | 359 | dev_err(&client->dev, "failed : add sysfs entries\n"); |
| 360 | − ret = -EIO; | |
| 361 | 360 | goto err_bled_mode; |
| 362 | 361 | } |
| 363 | 362 | |
| @@ -369,7 +368,6 @@ static int lm3639_probe(struct i2c_client *client, · 5 unmodified lines | ||
| 369 | 368 | &client->dev, &pchip->cdev_flash); |
| 370 | 369 | if (ret < 0) { |
| 371 | 370 | dev_err(&client->dev, "fail : flash register\n"); |
| 372 | − ret = -EIO; | |
| 373 | 371 | goto err_flash; |
| 374 | 372 | } |
| 375 | 373 | |
| @@ -381,7 +379,6 @@ static int lm3639_probe(struct i2c_client *client, · 5 unmodified lines | ||
| 381 | 379 | &client->dev, &pchip->cdev_torch); |
| 382 | 380 | if (ret < 0) { |
| 383 | 381 | dev_err(&client->dev, "fail : torch register\n"); |
| 384 | − ret = -EIO; | |
| 385 | 382 | goto err_torch; |
| 386 | 383 | } |
| 387 | 384 | |
| @@ -180,7 +180,7 @@ static int lms283gf05_probe(struct spi_device *spi) · 179 unmodified lines | ||
| 180 | 180 | st->spi = spi; |
| 181 | 181 | st->ld = ld; |
| 182 | 182 | |
| 183 | − dev_set_drvdata(&spi->dev, st); | |
| 183 | + spi_set_drvdata(spi, st); | |
| 184 | 184 | |
| 185 | 185 | /* kick in the LCD */ |
| 186 | 186 | if (pdata) |
| @@ -192,7 +192,7 @@ static int lms283gf05_probe(struct spi_device *spi) · 5 unmodified lines | ||
| 192 | 192 | |
| 193 | 193 | static int lms283gf05_remove(struct spi_device *spi) |
| 194 | 194 | { |
| 195 | − struct lms283gf05_state *st = dev_get_drvdata(&spi->dev); | |
| 195 | + struct lms283gf05_state *st = spi_get_drvdata(spi); | |
| 196 | 196 | |
| 197 | 197 | lcd_device_unregister(st->ld); |
| 198 | 198 | |
| @@ -0,0 +1,441 @@ | ||
| 1 | +/* | |
| 2 | + * lms501kf03 TFT LCD panel driver. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2012 Samsung Electronics Co., Ltd. | |
| 5 | + * Author: Jingoo Han <jg1.han@samsung.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License as published by the | |
| 9 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 10 | + * option) any later version. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/backlight.h> | |
| 14 | +#include <linux/delay.h> | |
| 15 | +#include <linux/fb.h> | |
| 16 | +#include <linux/gpio.h> | |
| 17 | +#include <linux/lcd.h> | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/spi/spi.h> | |
| 20 | +#include <linux/wait.h> | |
| 21 | + | |
| 22 | +#define COMMAND_ONLY 0x00 | |
| 23 | +#define DATA_ONLY 0x01 | |
| 24 | + | |
| 25 | +struct lms501kf03 { | |
| 26 | + struct device *dev; | |
| 27 | + struct spi_device *spi; | |
| 28 | + unsigned int power; | |
| 29 | + struct lcd_device *ld; | |
| 30 | + struct lcd_platform_data *lcd_pd; | |
| 31 | +}; | |
| 32 | + | |
| 33 | +static const unsigned char seq_password[] = { | |
| 34 | + 0xb9, 0xff, 0x83, 0x69, | |
| 35 | +}; | |
| 36 | + | |
| 37 | +static const unsigned char seq_power[] = { | |
| 38 | + 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28, | |
| 39 | + 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, | |
| 40 | +}; | |
| 41 | + | |
| 42 | +static const unsigned char seq_display[] = { | |
| 43 | + 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00, | |
| 44 | + 0x00, 0x00, 0x03, 0x03, 0x00, 0x01, | |
| 45 | +}; | |
| 46 | + | |
| 47 | +static const unsigned char seq_rgb_if[] = { | |
| 48 | + 0xb3, 0x09, | |
| 49 | +}; | |
| 50 | + | |
| 51 | +static const unsigned char seq_display_inv[] = { | |
| 52 | + 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06, | |
| 53 | +}; | |
| 54 | + | |
| 55 | +static const unsigned char seq_vcom[] = { | |
| 56 | + 0xb6, 0x4c, 0x2e, | |
| 57 | +}; | |
| 58 | + | |
| 59 | +static const unsigned char seq_gate[] = { | |
| 60 | + 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13, | |
| 61 | + 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75, | |
| 62 | + 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07, | |
| 63 | +}; | |
| 64 | + | |
| 65 | +static const unsigned char seq_panel[] = { | |
| 66 | + 0xcc, 0x02, | |
| 67 | +}; | |
| 68 | + | |
| 69 | +static const unsigned char seq_col_mod[] = { | |
| 70 | + 0x3a, 0x77, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +static const unsigned char seq_w_gamma[] = { | |
| 74 | + 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a, | |
| 75 | + 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04, | |
| 76 | + 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16, | |
| 77 | + 0x18, 0x16, 0x17, 0x0d, 0x15, | |
| 78 | +}; | |
| 79 | + | |
| 80 | +static const unsigned char seq_rgb_gamma[] = { | |
| 81 | + 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c, | |
| 82 | + 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92, | |
| 83 | + 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde, | |
| 84 | + 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb, | |
| 85 | + 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a, | |
| 86 | + 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, | |
| 87 | + 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca, | |
| 88 | + 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe, | |
| 89 | + 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17, | |
| 90 | + 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63, | |
| 91 | + 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0, | |
| 92 | + 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00, | |
| 93 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 94 | +}; | |
| 95 | + | |
| 96 | +static const unsigned char seq_up_dn[] = { | |
| 97 | + 0x36, 0x10, | |
| 98 | +}; | |
| 99 | + | |
| 100 | +static const unsigned char seq_sleep_in[] = { | |
| 101 | + 0x10, | |
| 102 | +}; | |
| 103 | + | |
| 104 | +static const unsigned char seq_sleep_out[] = { | |
| 105 | + 0x11, | |
| 106 | +}; | |
| 107 | + | |
| 108 | +static const unsigned char seq_display_on[] = { | |
| 109 | + 0x29, | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static const unsigned char seq_display_off[] = { | |
| 113 | + 0x10, | |
| 114 | +}; | |
| 115 | + | |
| 116 | +static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data) | |
| 117 | +{ | |
| 118 | + u16 buf[1]; | |
| 119 | + struct spi_message msg; | |
| 120 | + | |
| 121 | + struct spi_transfer xfer = { | |
| 122 | + .len = 2, | |
| 123 | + .tx_buf = buf, | |
| 124 | + }; | |
| 125 | + | |
| 126 | + buf[0] = (addr << 8) | data; | |
| 127 | + | |
| 128 | + spi_message_init(&msg); | |
| 129 | + spi_message_add_tail(&xfer, &msg); | |
| 130 | + | |
| 131 | + return spi_sync(lcd->spi, &msg); | |
| 132 | +} | |
| 133 | + | |
| 134 | +static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address, | |
| 135 | + unsigned char command) | |
| 136 | +{ | |
| 137 | + return lms501kf03_spi_write_byte(lcd, address, command); | |
| 138 | +} | |
| 139 | + | |
| 140 | +static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd, | |
| 141 | + const unsigned char *wbuf, | |
| 142 | + unsigned int len) | |
| 143 | +{ | |
| 144 | + int ret = 0, i = 0; | |
| 145 | + | |
| 146 | + while (i < len) { | |
| 147 | + if (i == 0) | |
| 148 | + ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]); | |
| 149 | + else | |
| 150 | + ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]); | |
| 151 | + if (ret) | |
| 152 | + break; | |
| 153 | + i += 1; | |
| 154 | + } | |
| 155 | + | |
| 156 | + return ret; | |
| 157 | +} | |
| 158 | + | |
| 159 | +static int lms501kf03_ldi_init(struct lms501kf03 *lcd) | |
| 160 | +{ | |
| 161 | + int ret, i; | |
| 162 | + static const unsigned char *init_seq[] = { | |
| 163 | + seq_password, | |
| 164 | + seq_power, | |
| 165 | + seq_display, | |
| 166 | + seq_rgb_if, | |
| 167 | + seq_display_inv, | |
| 168 | + seq_vcom, | |
| 169 | + seq_gate, | |
| 170 | + seq_panel, | |
| 171 | + seq_col_mod, | |
| 172 | + seq_w_gamma, | |
| 173 | + seq_rgb_gamma, | |
| 174 | + seq_sleep_out, | |
| 175 | + }; | |
| 176 | + | |
| 177 | + static const unsigned int size_seq[] = { | |
| 178 | + ARRAY_SIZE(seq_password), | |
| 179 | + ARRAY_SIZE(seq_power), | |
| 180 | + ARRAY_SIZE(seq_display), | |
| 181 | + ARRAY_SIZE(seq_rgb_if), | |
| 182 | + ARRAY_SIZE(seq_display_inv), | |
| 183 | + ARRAY_SIZE(seq_vcom), | |
| 184 | + ARRAY_SIZE(seq_gate), | |
| 185 | + ARRAY_SIZE(seq_panel), | |
| 186 | + ARRAY_SIZE(seq_col_mod), | |
| 187 | + ARRAY_SIZE(seq_w_gamma), | |
| 188 | + ARRAY_SIZE(seq_rgb_gamma), | |
| 189 | + ARRAY_SIZE(seq_sleep_out), | |
| 190 | + }; | |
| 191 | + | |
| 192 | + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { | |
| 193 | + ret = lms501kf03_panel_send_sequence(lcd, init_seq[i], | |
| 194 | + size_seq[i]); | |
| 195 | + if (ret) | |
| 196 | + break; | |
| 197 | + } | |
| 198 | + /* | |
| 199 | + * According to the datasheet, 120ms delay time is required. | |
| 200 | + * After sleep out sequence, command is blocked for 120ms. | |
| 201 | + * Thus, LDI should wait for 120ms. | |
| 202 | + */ | |
| 203 | + msleep(120); | |
| 204 | + | |
| 205 | + return ret; | |
| 206 | +} | |
| 207 | + | |
| 208 | +static int lms501kf03_ldi_enable(struct lms501kf03 *lcd) | |
| 209 | +{ | |
| 210 | + return lms501kf03_panel_send_sequence(lcd, seq_display_on, | |
| 211 | + ARRAY_SIZE(seq_display_on)); | |
| 212 | +} | |
| 213 | + | |
| 214 | +static int lms501kf03_ldi_disable(struct lms501kf03 *lcd) | |
| 215 | +{ | |
| 216 | + return lms501kf03_panel_send_sequence(lcd, seq_display_off, | |
| 217 | + ARRAY_SIZE(seq_display_off)); | |
| 218 | +} | |
| 219 | + | |
| 220 | +static int lms501kf03_power_is_on(int power) | |
| 221 | +{ | |
| 222 | + return (power) <= FB_BLANK_NORMAL; | |
| 223 | +} | |
| 224 | + | |
| 225 | +static int lms501kf03_power_on(struct lms501kf03 *lcd) | |
| 226 | +{ | |
| 227 | + int ret = 0; | |
| 228 | + struct lcd_platform_data *pd; | |
| 229 | + | |
| 230 | + pd = lcd->lcd_pd; | |
| 231 | + | |
| 232 | + if (!pd->power_on) { | |
| 233 | + dev_err(lcd->dev, "power_on is NULL.\n"); | |
| 234 | + return -EINVAL; | |
| 235 | + } else { | |
| 236 | + pd->power_on(lcd->ld, 1); | |
| 237 | + msleep(pd->power_on_delay); | |
| 238 | + } | |
| 239 | + | |
| 240 | + if (!pd->reset) { | |
| 241 | + dev_err(lcd->dev, "reset is NULL.\n"); | |
| 242 | + return -EINVAL; | |
| 243 | + } else { | |
| 244 | + pd->reset(lcd->ld); | |
| 245 | + msleep(pd->reset_delay); | |
| 246 | + } | |
| 247 | + | |
| 248 | + ret = lms501kf03_ldi_init(lcd); | |
| 249 | + if (ret) { | |
| 250 | + dev_err(lcd->dev, "failed to initialize ldi.\n"); | |
| 251 | + return ret; | |
| 252 | + } | |
| 253 | + | |
| 254 | + ret = lms501kf03_ldi_enable(lcd); | |
| 255 | + if (ret) { | |
| 256 | + dev_err(lcd->dev, "failed to enable ldi.\n"); | |
| 257 | + return ret; | |
| 258 | + } | |
| 259 | + | |
| 260 | + return 0; | |
| 261 | +} | |
| 262 | + | |
| 263 | +static int lms501kf03_power_off(struct lms501kf03 *lcd) | |
| 264 | +{ | |
| 265 | + int ret = 0; | |
| 266 | + struct lcd_platform_data *pd; | |
| 267 | + | |
| 268 | + pd = lcd->lcd_pd; | |
| 269 | + | |
| 270 | + ret = lms501kf03_ldi_disable(lcd); | |
| 271 | + if (ret) { | |
| 272 | + dev_err(lcd->dev, "lcd setting failed.\n"); | |
| 273 | + return -EIO; | |
| 274 | + } | |
| 275 | + | |
| 276 | + msleep(pd->power_off_delay); | |
| 277 | + | |
| 278 | + pd->power_on(lcd->ld, 0); | |
| 279 | + | |
| 280 | + return 0; | |
| 281 | +} | |
| 282 | + | |
| 283 | +static int lms501kf03_power(struct lms501kf03 *lcd, int power) | |
| 284 | +{ | |
| 285 | + int ret = 0; | |
| 286 | + | |
| 287 | + if (lms501kf03_power_is_on(power) && | |
| 288 | + !lms501kf03_power_is_on(lcd->power)) | |
| 289 | + ret = lms501kf03_power_on(lcd); | |
| 290 | + else if (!lms501kf03_power_is_on(power) && | |
| 291 | + lms501kf03_power_is_on(lcd->power)) | |
| 292 | + ret = lms501kf03_power_off(lcd); | |
| 293 | + | |
| 294 | + if (!ret) | |
| 295 | + lcd->power = power; | |
| 296 | + | |
| 297 | + return ret; | |
| 298 | +} | |
| 299 | + | |
| 300 | +static int lms501kf03_get_power(struct lcd_device *ld) | |
| 301 | +{ | |
| 302 | + struct lms501kf03 *lcd = lcd_get_data(ld); | |
| 303 | + | |
| 304 | + return lcd->power; | |
| 305 | +} | |
| 306 | + | |
| 307 | +static int lms501kf03_set_power(struct lcd_device *ld, int power) | |
| 308 | +{ | |
| 309 | + struct lms501kf03 *lcd = lcd_get_data(ld); | |
| 310 | + | |
| 311 | + if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && | |
| 312 | + power != FB_BLANK_NORMAL) { | |
| 313 | + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); | |
| 314 | + return -EINVAL; | |
| 315 | + } | |
| 316 | + | |
| 317 | + return lms501kf03_power(lcd, power); | |
| 318 | +} | |
| 319 | + | |
| 320 | +static struct lcd_ops lms501kf03_lcd_ops = { | |
| 321 | + .get_power = lms501kf03_get_power, | |
| 322 | + .set_power = lms501kf03_set_power, | |
| 323 | +}; | |
| 324 | + | |
| 325 | +static int lms501kf03_probe(struct spi_device *spi) | |
| 326 | +{ | |
| 327 | + struct lms501kf03 *lcd = NULL; | |
| 328 | + struct lcd_device *ld = NULL; | |
| 329 | + int ret = 0; | |
| 330 | + | |
| 331 | + lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL); | |
| 332 | + if (!lcd) | |
| 333 | + return -ENOMEM; | |
| 334 | + | |
| 335 | + /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */ | |
| 336 | + spi->bits_per_word = 9; | |
| 337 | + | |
| 338 | + ret = spi_setup(spi); | |
| 339 | + if (ret < 0) { | |
| 340 | + dev_err(&spi->dev, "spi setup failed.\n"); | |
| 341 | + return ret; | |
| 342 | + } | |
| 343 | + | |
| 344 | + lcd->spi = spi; | |
| 345 | + lcd->dev = &spi->dev; | |
| 346 | + | |
| 347 | + lcd->lcd_pd = spi->dev.platform_data; | |
| 348 | + if (!lcd->lcd_pd) { | |
| 349 | + dev_err(&spi->dev, "platform data is NULL\n"); | |
| 350 | + return -EINVAL; | |
| 351 | + } | |
| 352 | + | |
| 353 | + ld = lcd_device_register("lms501kf03", &spi->dev, lcd, | |
| 354 | + &lms501kf03_lcd_ops); | |
| 355 | + if (IS_ERR(ld)) | |
| 356 | + return PTR_ERR(ld); | |
| 357 | + | |
| 358 | + lcd->ld = ld; | |
| 359 | + | |
| 360 | + if (!lcd->lcd_pd->lcd_enabled) { | |
| 361 | + /* | |
| 362 | + * if lcd panel was off from bootloader then | |
| 363 | + * current lcd status is powerdown and then | |
| 364 | + * it enables lcd panel. | |
| 365 | + */ | |
| 366 | + lcd->power = FB_BLANK_POWERDOWN; | |
| 367 | + | |
| 368 | + lms501kf03_power(lcd, FB_BLANK_UNBLANK); | |
| 369 | + } else { | |
| 370 | + lcd->power = FB_BLANK_UNBLANK; | |
| 371 | + } | |
| 372 | + | |
| 373 | + spi_set_drvdata(spi, lcd); | |
| 374 | + | |
| 375 | + dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n"); | |
| 376 | + | |
| 377 | + return 0; | |
| 378 | +} | |
| 379 | + | |
| 380 | +static int lms501kf03_remove(struct spi_device *spi) | |
| 381 | +{ | |
| 382 | + struct lms501kf03 *lcd = spi_get_drvdata(spi); | |
| 383 | + | |
| 384 | + lms501kf03_power(lcd, FB_BLANK_POWERDOWN); | |
| 385 | + lcd_device_unregister(lcd->ld); | |
| 386 | + | |
| 387 | + return 0; | |
| 388 | +} | |
| 389 | + | |
| 390 | +#if defined(CONFIG_PM) | |
| 391 | + | |
| 392 | +static int lms501kf03_suspend(struct spi_device *spi, pm_message_t mesg) | |
| 393 | +{ | |
| 394 | + struct lms501kf03 *lcd = spi_get_drvdata(spi); | |
| 395 | + | |
| 396 | + dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); | |
| 397 | + | |
| 398 | + /* | |
| 399 | + * when lcd panel is suspend, lcd panel becomes off | |
| 400 | + * regardless of status. | |
| 401 | + */ | |
| 402 | + return lms501kf03_power(lcd, FB_BLANK_POWERDOWN); | |
| 403 | +} | |
| 404 | + | |
| 405 | +static int lms501kf03_resume(struct spi_device *spi) | |
| 406 | +{ | |
| 407 | + struct lms501kf03 *lcd = spi_get_drvdata(spi); | |
| 408 | + | |
| 409 | + lcd->power = FB_BLANK_POWERDOWN; | |
| 410 | + | |
| 411 | + return lms501kf03_power(lcd, FB_BLANK_UNBLANK); | |
| 412 | +} | |
| 413 | +#else | |
| 414 | +#define lms501kf03_suspend NULL | |
| 415 | +#define lms501kf03_resume NULL | |
| 416 | +#endif | |
| 417 | + | |
| 418 | +static void lms501kf03_shutdown(struct spi_device *spi) | |
| 419 | +{ | |
| 420 | + struct lms501kf03 *lcd = spi_get_drvdata(spi); | |
| 421 | + | |
| 422 | + lms501kf03_power(lcd, FB_BLANK_POWERDOWN); | |
| 423 | +} | |
| 424 | + | |
| 425 | +static struct spi_driver lms501kf03_driver = { | |
| 426 | + .driver = { | |
| 427 | + .name = "lms501kf03", | |
| 428 | + .owner = THIS_MODULE, | |
| 429 | + }, | |
| 430 | + .probe = lms501kf03_probe, | |
| 431 | + .remove = lms501kf03_remove, | |
| 432 | + .shutdown = lms501kf03_shutdown, | |
| 433 | + .suspend = lms501kf03_suspend, | |
| 434 | + .resume = lms501kf03_resume, | |
| 435 | +}; | |
| 436 | + | |
| 437 | +module_spi_driver(lms501kf03_driver); | |
| 438 | + | |
| 439 | +MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | |
| 440 | +MODULE_DESCRIPTION("lms501kf03 LCD Driver"); | |
| 441 | +MODULE_LICENSE("GPL"); | |
| @@ -17,21 +17,48 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/platform_data/lp855x.h> |
| 18 | 18 | #include <linux/pwm.h> |
| 19 | 19 | |
| 20 | −/* Registers */ | |
| 21 | −#define BRIGHTNESS_CTRL 0x00 | |
| 22 | −#define DEVICE_CTRL 0x01 | |
| 23 | −#define EEPROM_START 0xA0 | |
| 24 | −#define EEPROM_END 0xA7 | |
| 25 | −#define EPROM_START 0xA0 | |
| 26 | −#define EPROM_END 0xAF | |
| 20 | +/* LP8550/1/2/3/6 Registers */ | |
| 21 | +#define LP855X_BRIGHTNESS_CTRL 0x00 | |
| 22 | +#define LP855X_DEVICE_CTRL 0x01 | |
| 23 | +#define LP855X_EEPROM_START 0xA0 | |
| 24 | +#define LP855X_EEPROM_END 0xA7 | |
| 25 | +#define LP8556_EPROM_START 0xA0 | |
| 26 | +#define LP8556_EPROM_END 0xAF | |
| 27 | + | |
| 28 | +/* LP8557 Registers */ | |
| 29 | +#define LP8557_BL_CMD 0x00 | |
| 30 | +#define LP8557_BL_MASK 0x01 | |
| 31 | +#define LP8557_BL_ON 0x01 | |
| 32 | +#define LP8557_BL_OFF 0x00 | |
| 33 | +#define LP8557_BRIGHTNESS_CTRL 0x04 | |
| 34 | +#define LP8557_CONFIG 0x10 | |
| 35 | +#define LP8557_EPROM_START 0x10 | |
| 36 | +#define LP8557_EPROM_END 0x1E | |
| 27 | 37 | |
| 28 | 38 | #define BUF_SIZE 20 |
| 29 | 39 | #define DEFAULT_BL_NAME "lcd-backlight" |
| 30 | 40 | #define MAX_BRIGHTNESS 255 |
| 31 | 41 | |
| 42 | +struct lp855x; | |
| 43 | + | |
| 44 | +/* | |
| 45 | + * struct lp855x_device_config | |
| 46 | + * @pre_init_device: init device function call before updating the brightness | |
| 47 | + * @reg_brightness: register address for brigthenss control | |
| 48 | + * @reg_devicectrl: register address for device control | |
| 49 | + * @post_init_device: late init device function call | |
| 50 | + */ | |
| 51 | +struct lp855x_device_config { | |
| 52 | + int (*pre_init_device)(struct lp855x *); | |
| 53 | + u8 reg_brightness; | |
| 54 | + u8 reg_devicectrl; | |
| 55 | + int (*post_init_device)(struct lp855x *); | |
| 56 | +}; | |
| 57 | + | |
| 32 | 58 | struct lp855x { |
| 33 | 59 | const char *chipname; |
| 34 | 60 | enum lp855x_chip_id chip_id; |
| 61 | + struct lp855x_device_config *cfg; | |
| 35 | 62 | struct i2c_client *client; |
| 36 | 63 | struct backlight_device *bl; |
| 37 | 64 | struct device *dev; |
| @@ -39,9 +66,15 @@ struct lp855x { · 1 unmodified line | ||
| 39 | 66 | struct pwm_device *pwm; |
| 40 | 67 | }; |
| 41 | 68 | |
| 42 | −static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data) | |
| 69 | +static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) | |
| 70 | +{ | |
| 71 | + return i2c_smbus_write_byte_data(lp->client, reg, data); | |
| 72 | +} | |
| 73 | + | |
| 74 | +static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data) | |
| 43 | 75 | { |
| 44 | 76 | int ret; |
| 77 | + u8 tmp; | |
| 45 | 78 | |
| 46 | 79 | ret = i2c_smbus_read_byte_data(lp->client, reg); |
| 47 | 80 | if (ret < 0) { |
| @@ -49,13 +82,11 @@ static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data) · 1 unmodified line | ||
| 49 | 82 | return ret; |
| 50 | 83 | } |
| 51 | 84 | |
| 52 | − *data = (u8)ret; | |
| 53 | − return 0; | |
| 54 | −} | |
| 85 | + tmp = (u8)ret; | |
| 86 | + tmp &= ~mask; | |
| 87 | + tmp |= data & mask; | |
| 55 | 88 | |
| 56 | −static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) | |
| 57 | −{ | |
| 58 | − return i2c_smbus_write_byte_data(lp->client, reg, data); | |
| 89 | + return lp855x_write_byte(lp, reg, tmp); | |
| 59 | 90 | } |
| 60 | 91 | |
| 61 | 92 | static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) |
| @@ -67,12 +98,16 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) · 5 unmodified lines | ||
| 67 | 98 | case LP8551: |
| 68 | 99 | case LP8552: |
| 69 | 100 | case LP8553: |
| 70 | − start = EEPROM_START; | |
| 71 | − end = EEPROM_END; | |
| 101 | + start = LP855X_EEPROM_START; | |
| 102 | + end = LP855X_EEPROM_END; | |
| 72 | 103 | break; |
| 73 | 104 | case LP8556: |
| 74 | − start = EPROM_START; | |
| 75 | − end = EPROM_END; | |
| 105 | + start = LP8556_EPROM_START; | |
| 106 | + end = LP8556_EPROM_END; | |
| 107 | + break; | |
| 108 | + case LP8557: | |
| 109 | + start = LP8557_EPROM_START; | |
| 110 | + end = LP8557_EPROM_END; | |
| 76 | 111 | break; |
| 77 | 112 | default: |
| 78 | 113 | return false; |
| @@ -81,21 +116,76 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) · 2 unmodified lines | ||
| 81 | 116 | return (addr >= start && addr <= end); |
| 82 | 117 | } |
| 83 | 118 | |
| 84 | −static int lp855x_init_registers(struct lp855x *lp) | |
| 119 | +static int lp8557_bl_off(struct lp855x *lp) | |
| 120 | +{ | |
| 121 | + /* BL_ON = 0 before updating EPROM settings */ | |
| 122 | + return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK, | |
| 123 | + LP8557_BL_OFF); | |
| 124 | +} | |
| 125 | + | |
| 126 | +static int lp8557_bl_on(struct lp855x *lp) | |
| 127 | +{ | |
| 128 | + /* BL_ON = 1 after updating EPROM settings */ | |
| 129 | + return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK, | |
| 130 | + LP8557_BL_ON); | |
| 131 | +} | |
| 132 | + | |
| 133 | +static struct lp855x_device_config lp855x_dev_cfg = { | |
| 134 | + .reg_brightness = LP855X_BRIGHTNESS_CTRL, | |
| 135 | + .reg_devicectrl = LP855X_DEVICE_CTRL, | |
| 136 | +}; | |
| 137 | + | |
| 138 | +static struct lp855x_device_config lp8557_dev_cfg = { | |
| 139 | + .reg_brightness = LP8557_BRIGHTNESS_CTRL, | |
| 140 | + .reg_devicectrl = LP8557_CONFIG, | |
| 141 | + .pre_init_device = lp8557_bl_off, | |
| 142 | + .post_init_device = lp8557_bl_on, | |
| 143 | +}; | |
| 144 | + | |
| 145 | +/* | |
| 146 | + * Device specific configuration flow | |
| 147 | + * | |
| 148 | + * a) pre_init_device(optional) | |
| 149 | + * b) update the brightness register | |
| 150 | + * c) update device control register | |
| 151 | + * d) update ROM area(optional) | |
| 152 | + * e) post_init_device(optional) | |
| 153 | + * | |
| 154 | + */ | |
| 155 | +static int lp855x_configure(struct lp855x *lp) | |
| 85 | 156 | { |
| 86 | 157 | u8 val, addr; |
| 87 | 158 | int i, ret; |
| 88 | 159 | struct lp855x_platform_data *pd = lp->pdata; |
| 89 | 160 | |
| 161 | + switch (lp->chip_id) { | |
| 162 | + case LP8550 ... LP8556: | |
| 163 | + lp->cfg = &lp855x_dev_cfg; | |
| 164 | + break; | |
| 165 | + case LP8557: | |
| 166 | + lp->cfg = &lp8557_dev_cfg; | |
| 167 | + break; | |
| 168 | + default: | |
| 169 | + return -EINVAL; | |
| 170 | + } | |
| 171 | + | |
| 172 | + if (lp->cfg->pre_init_device) { | |
| 173 | + ret = lp->cfg->pre_init_device(lp); | |
| 174 | + if (ret) { | |
| 175 | + dev_err(lp->dev, "pre init device err: %d\n", ret); | |
| 176 | + goto err; | |
| 177 | + } | |
| 178 | + } | |
| 179 | + | |
| 90 | 180 | val = pd->initial_brightness; |
| 91 | − ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); | |
| 181 | + ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val); | |
| 92 | 182 | if (ret) |
| 93 | − return ret; | |
| 183 | + goto err; | |
| 94 | 184 | |
| 95 | 185 | val = pd->device_control; |
| 96 | − ret = lp855x_write_byte(lp, DEVICE_CTRL, val); | |
| 186 | + ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val); | |
| 97 | 187 | if (ret) |
| 98 | − return ret; | |
| 188 | + goto err; | |
| 99 | 189 | |
| 100 | 190 | if (pd->load_new_rom_data && pd->size_program) { |
| 101 | 191 | for (i = 0; i < pd->size_program; i++) { |
| @@ -106,10 +196,21 @@ static int lp855x_init_registers(struct lp855x *lp) · 4 unmodified lines | ||
| 106 | 196 | |
| 107 | 197 | ret = lp855x_write_byte(lp, addr, val); |
| 108 | 198 | if (ret) |
| 109 | − return ret; | |
| 199 | + goto err; | |
| 200 | + } | |
| 201 | + } | |
| 202 | + | |
| 203 | + if (lp->cfg->post_init_device) { | |
| 204 | + ret = lp->cfg->post_init_device(lp); | |
| 205 | + if (ret) { | |
| 206 | + dev_err(lp->dev, "post init device err: %d\n", ret); | |
| 207 | + goto err; | |
| 110 | 208 | } |
| 111 | 209 | } |
| 112 | 210 | |
| 211 | + return 0; | |
| 212 | + | |
| 213 | +err: | |
| 113 | 214 | return ret; |
| 114 | 215 | } |
| 115 | 216 | |
| @@ -151,7 +252,7 @@ static int lp855x_bl_update_status(struct backlight_device *bl) · 35 unmodified lines | ||
| 151 | 252 | |
| 152 | 253 | } else if (mode == REGISTER_BASED) { |
| 153 | 254 | u8 val = bl->props.brightness; |
| 154 | − lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); | |
| 255 | + lp855x_write_byte(lp, lp->cfg->reg_brightness, val); | |
| 155 | 256 | } |
| 156 | 257 | |
| 157 | 258 | return 0; |
| @@ -159,16 +260,6 @@ static int lp855x_bl_update_status(struct backlight_device *bl) · 1 unmodified line | ||
| 159 | 260 | |
| 160 | 261 | static int lp855x_bl_get_brightness(struct backlight_device *bl) |
| 161 | 262 | { |
| 162 | − struct lp855x *lp = bl_get_data(bl); | |
| 163 | − enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode; | |
| 164 | − | |
| 165 | − if (mode == REGISTER_BASED) { | |
| 166 | − u8 val = 0; | |
| 167 | − | |
| 168 | − lp855x_read_byte(lp, BRIGHTNESS_CTRL, &val); | |
| 169 | − bl->props.brightness = val; | |
| 170 | − } | |
| 171 | − | |
| 172 | 263 | return bl->props.brightness; |
| 173 | 264 | } |
| 174 | 265 | |
| @@ -271,11 +362,10 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) · 96 unmodified lines | ||
| 271 | 362 | lp->chip_id = id->driver_data; |
| 272 | 363 | i2c_set_clientdata(cl, lp); |
| 273 | 364 | |
| 274 | − ret = lp855x_init_registers(lp); | |
| 365 | + ret = lp855x_configure(lp); | |
| 275 | 366 | if (ret) { |
| 276 | − dev_err(lp->dev, "i2c communication err: %d", ret); | |
| 277 | − if (mode == REGISTER_BASED) | |
| 278 | − goto err_dev; | |
| 367 | + dev_err(lp->dev, "device config err: %d", ret); | |
| 368 | + goto err_dev; | |
| 279 | 369 | } |
| 280 | 370 | |
| 281 | 371 | ret = lp855x_backlight_register(lp); |
| @@ -318,6 +408,7 @@ static const struct i2c_device_id lp855x_ids[] = { · 36 unmodified lines | ||
| 318 | 408 | {"lp8552", LP8552}, |
| 319 | 409 | {"lp8553", LP8553}, |
| 320 | 410 | {"lp8556", LP8556}, |
| 411 | + {"lp8557", LP8557}, | |
| 321 | 412 | { } |
| 322 | 413 | }; |
| 323 | 414 | MODULE_DEVICE_TABLE(i2c, lp855x_ids); |
| @@ -252,7 +252,7 @@ static int ltv350qv_probe(struct spi_device *spi) · 251 unmodified lines | ||
| 252 | 252 | if (ret) |
| 253 | 253 | goto out_unregister; |
| 254 | 254 | |
| 255 | − dev_set_drvdata(&spi->dev, lcd); | |
| 255 | + spi_set_drvdata(spi, lcd); | |
| 256 | 256 | |
| 257 | 257 | return 0; |
| 258 | 258 | |
| @@ -263,7 +263,7 @@ out_unregister: · 4 unmodified lines | ||
| 263 | 263 | |
| 264 | 264 | static int ltv350qv_remove(struct spi_device *spi) |
| 265 | 265 | { |
| 266 | − struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); | |
| 266 | + struct ltv350qv *lcd = spi_get_drvdata(spi); | |
| 267 | 267 | |
| 268 | 268 | ltv350qv_power(lcd, FB_BLANK_POWERDOWN); |
| 269 | 269 | lcd_device_unregister(lcd->ld); |
| @@ -274,14 +274,14 @@ static int ltv350qv_remove(struct spi_device *spi) · 4 unmodified lines | ||
| 274 | 274 | #ifdef CONFIG_PM |
| 275 | 275 | static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state) |
| 276 | 276 | { |
| 277 | − struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); | |
| 277 | + struct ltv350qv *lcd = spi_get_drvdata(spi); | |
| 278 | 278 | |
| 279 | 279 | return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 | static int ltv350qv_resume(struct spi_device *spi) |
| 283 | 283 | { |
| 284 | − struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); | |
| 284 | + struct ltv350qv *lcd = spi_get_drvdata(spi); | |
| 285 | 285 | |
| 286 | 286 | return ltv350qv_power(lcd, FB_BLANK_UNBLANK); |
| 287 | 287 | } |
| @@ -293,7 +293,7 @@ static int ltv350qv_resume(struct spi_device *spi) · 5 unmodified lines | ||
| 293 | 293 | /* Power down all displays on reboot, poweroff or halt */ |
| 294 | 294 | static void ltv350qv_shutdown(struct spi_device *spi) |
| 295 | 295 | { |
| 296 | − struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); | |
| 296 | + struct ltv350qv *lcd = spi_get_drvdata(spi); | |
| 297 | 297 | |
| 298 | 298 | ltv350qv_power(lcd, FB_BLANK_POWERDOWN); |
| 299 | 299 | } |
| @@ -77,7 +77,7 @@ static void omapbl_blank(struct omap_backlight *bl, int mode) · 76 unmodified lines | ||
| 77 | 77 | static int omapbl_suspend(struct platform_device *pdev, pm_message_t state) |
| 78 | 78 | { |
| 79 | 79 | struct backlight_device *dev = platform_get_drvdata(pdev); |
| 80 | − struct omap_backlight *bl = dev_get_drvdata(&dev->dev); | |
| 80 | + struct omap_backlight *bl = bl_get_data(dev); | |
| 81 | 81 | |
| 82 | 82 | omapbl_blank(bl, FB_BLANK_POWERDOWN); |
| 83 | 83 | return 0; |
| @@ -86,7 +86,7 @@ static int omapbl_suspend(struct platform_device *pdev, pm_message_t state) · 2 unmodified lines | ||
| 86 | 86 | static int omapbl_resume(struct platform_device *pdev) |
| 87 | 87 | { |
| 88 | 88 | struct backlight_device *dev = platform_get_drvdata(pdev); |
| 89 | − struct omap_backlight *bl = dev_get_drvdata(&dev->dev); | |
| 89 | + struct omap_backlight *bl = bl_get_data(dev); | |
| 90 | 90 | |
| 91 | 91 | omapbl_blank(bl, bl->powermode); |
| 92 | 92 | return 0; |
| @@ -98,7 +98,7 @@ static int omapbl_resume(struct platform_device *pdev) · 5 unmodified lines | ||
| 98 | 98 | |
| 99 | 99 | static int omapbl_set_power(struct backlight_device *dev, int state) |
| 100 | 100 | { |
| 101 | − struct omap_backlight *bl = dev_get_drvdata(&dev->dev); | |
| 101 | + struct omap_backlight *bl = bl_get_data(dev); | |
| 102 | 102 | |
| 103 | 103 | omapbl_blank(bl, state); |
| 104 | 104 | bl->powermode = state; |
| @@ -108,7 +108,7 @@ static int omapbl_set_power(struct backlight_device *dev, int state) · 3 unmodified lines | ||
| 108 | 108 | |
| 109 | 109 | static int omapbl_update_status(struct backlight_device *dev) |
| 110 | 110 | { |
| 111 | − struct omap_backlight *bl = dev_get_drvdata(&dev->dev); | |
| 111 | + struct omap_backlight *bl = bl_get_data(dev); | |
| 112 | 112 | |
| 113 | 113 | if (bl->current_intensity != dev->props.brightness) { |
| 114 | 114 | if (bl->powermode == FB_BLANK_UNBLANK) |
| @@ -124,7 +124,7 @@ static int omapbl_update_status(struct backlight_device *dev) · 9 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | static int omapbl_get_intensity(struct backlight_device *dev) |
| 126 | 126 | { |
| 127 | − struct omap_backlight *bl = dev_get_drvdata(&dev->dev); | |
| 127 | + struct omap_backlight *bl = bl_get_data(dev); | |
| 128 | 128 | return bl->current_intensity; |
| 129 | 129 | } |
| 130 | 130 | |
| @@ -37,7 +37,7 @@ struct pwm_bl_data { · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | static int pwm_backlight_update_status(struct backlight_device *bl) |
| 39 | 39 | { |
| 40 | − struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); | |
| 40 | + struct pwm_bl_data *pb = bl_get_data(bl); | |
| 41 | 41 | int brightness = bl->props.brightness; |
| 42 | 42 | int max = bl->props.max_brightness; |
| 43 | 43 | |
| @@ -83,7 +83,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) · 39 unmodified lines | ||
| 83 | 83 | static int pwm_backlight_check_fb(struct backlight_device *bl, |
| 84 | 84 | struct fb_info *info) |
| 85 | 85 | { |
| 86 | − struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); | |
| 86 | + struct pwm_bl_data *pb = bl_get_data(bl); | |
| 87 | 87 | |
| 88 | 88 | return !pb->check_fb || pb->check_fb(pb->dev, info); |
| 89 | 89 | } |
| @@ -264,7 +264,7 @@ err_alloc: · 174 unmodified lines | ||
| 264 | 264 | static int pwm_backlight_remove(struct platform_device *pdev) |
| 265 | 265 | { |
| 266 | 266 | struct backlight_device *bl = platform_get_drvdata(pdev); |
| 267 | − struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); | |
| 267 | + struct pwm_bl_data *pb = bl_get_data(bl); | |
| 268 | 268 | |
| 269 | 269 | backlight_device_unregister(bl); |
| 270 | 270 | pwm_config(pb->pwm, 0, pb->period); |
| @@ -278,7 +278,7 @@ static int pwm_backlight_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 278 | 278 | static int pwm_backlight_suspend(struct device *dev) |
| 279 | 279 | { |
| 280 | 280 | struct backlight_device *bl = dev_get_drvdata(dev); |
| 281 | − struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); | |
| 281 | + struct pwm_bl_data *pb = bl_get_data(bl); | |
| 282 | 282 | |
| 283 | 283 | if (pb->notify) |
| 284 | 284 | pb->notify(pb->dev, 0); |
| @@ -9,28 +9,19 @@ · 8 unmodified lines | ||
| 9 | 9 | * under the terms of the GNU General Public License as published by the |
| 10 | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | 11 | * option) any later version. |
| 12 | − * | |
| 13 | − * This program is distributed in the hope that it will be useful, but | |
| 14 | − * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 16 | − * General Public License for more details. | |
| 17 | − * | |
| 18 | − * You should have received a copy of the GNU General Public License along | |
| 19 | − * with this program; if not, write to the Free Software Foundation, Inc., | |
| 20 | − * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 21 | 12 | */ |
| 22 | 13 | |
| 23 | −#include <linux/wait.h> | |
| 24 | −#include <linux/fb.h> | |
| 14 | +#include <linux/backlight.h> | |
| 25 | 15 | #include <linux/delay.h> |
| 16 | +#include <linux/fb.h> | |
| 26 | 17 | #include <linux/gpio.h> |
| 27 | −#include <linux/spi/spi.h> | |
| 28 | −#include <linux/irq.h> | |
| 29 | 18 | #include <linux/interrupt.h> |
| 19 | +#include <linux/irq.h> | |
| 30 | 20 | #include <linux/kernel.h> |
| 31 | 21 | #include <linux/lcd.h> |
| 32 | −#include <linux/backlight.h> | |
| 33 | 22 | #include <linux/module.h> |
| 23 | +#include <linux/spi/spi.h> | |
| 24 | +#include <linux/wait.h> | |
| 34 | 25 | |
| 35 | 26 | #include "s6e63m0_gamma.h" |
| 36 | 27 | |
| @@ -43,8 +34,6 @@ · 6 unmodified lines | ||
| 43 | 34 | #define MIN_BRIGHTNESS 0 |
| 44 | 35 | #define MAX_BRIGHTNESS 10 |
| 45 | 36 | |
| 46 | −#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) | |
| 47 | − | |
| 48 | 37 | struct s6e63m0 { |
| 49 | 38 | struct device *dev; |
| 50 | 39 | struct spi_device *spi; |
| @@ -57,7 +46,7 @@ struct s6e63m0 { · 6 unmodified lines | ||
| 57 | 46 | struct lcd_platform_data *lcd_pd; |
| 58 | 47 | }; |
| 59 | 48 | |
| 60 | −static const unsigned short SEQ_PANEL_CONDITION_SET[] = { | |
| 49 | +static const unsigned short seq_panel_condition_set[] = { | |
| 61 | 50 | 0xF8, 0x01, |
| 62 | 51 | DATA_ONLY, 0x27, |
| 63 | 52 | DATA_ONLY, 0x27, |
| @@ -76,7 +65,7 @@ static const unsigned short SEQ_PANEL_CONDITION_SET[] = { · 12 unmodified lines | ||
| 76 | 65 | ENDDEF, 0x0000 |
| 77 | 66 | }; |
| 78 | 67 | |
| 79 | −static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { | |
| 68 | +static const unsigned short seq_display_condition_set[] = { | |
| 80 | 69 | 0xf2, 0x02, |
| 81 | 70 | DATA_ONLY, 0x03, |
| 82 | 71 | DATA_ONLY, 0x1c, |
| @@ -90,7 +79,7 @@ static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { · 7 unmodified lines | ||
| 90 | 79 | ENDDEF, 0x0000 |
| 91 | 80 | }; |
| 92 | 81 | |
| 93 | −static const unsigned short SEQ_GAMMA_SETTING[] = { | |
| 82 | +static const unsigned short seq_gamma_setting[] = { | |
| 94 | 83 | 0xfa, 0x00, |
| 95 | 84 | DATA_ONLY, 0x18, |
| 96 | 85 | DATA_ONLY, 0x08, |
| @@ -119,7 +108,7 @@ static const unsigned short SEQ_GAMMA_SETTING[] = { · 22 unmodified lines | ||
| 119 | 108 | ENDDEF, 0x0000 |
| 120 | 109 | }; |
| 121 | 110 | |
| 122 | −static const unsigned short SEQ_ETC_CONDITION_SET[] = { | |
| 111 | +static const unsigned short seq_etc_condition_set[] = { | |
| 123 | 112 | 0xf6, 0x00, |
| 124 | 113 | DATA_ONLY, 0x8c, |
| 125 | 114 | DATA_ONLY, 0x07, |
| @@ -318,47 +307,47 @@ static const unsigned short SEQ_ETC_CONDITION_SET[] = { · 192 unmodified lines | ||
| 318 | 307 | ENDDEF, 0x0000 |
| 319 | 308 | }; |
| 320 | 309 | |
| 321 | −static const unsigned short SEQ_ACL_ON[] = { | |
| 310 | +static const unsigned short seq_acl_on[] = { | |
| 322 | 311 | /* ACL on */ |
| 323 | 312 | 0xc0, 0x01, |
| 324 | 313 | |
| 325 | 314 | ENDDEF, 0x0000 |
| 326 | 315 | }; |
| 327 | 316 | |
| 328 | −static const unsigned short SEQ_ACL_OFF[] = { | |
| 317 | +static const unsigned short seq_acl_off[] = { | |
| 329 | 318 | /* ACL off */ |
| 330 | 319 | 0xc0, 0x00, |
| 331 | 320 | |
| 332 | 321 | ENDDEF, 0x0000 |
| 333 | 322 | }; |
| 334 | 323 | |
| 335 | −static const unsigned short SEQ_ELVSS_ON[] = { | |
| 324 | +static const unsigned short seq_elvss_on[] = { | |
| 336 | 325 | /* ELVSS on */ |
| 337 | 326 | 0xb1, 0x0b, |
| 338 | 327 | |
| 339 | 328 | ENDDEF, 0x0000 |
| 340 | 329 | }; |
| 341 | 330 | |
| 342 | −static const unsigned short SEQ_ELVSS_OFF[] = { | |
| 331 | +static const unsigned short seq_elvss_off[] = { | |
| 343 | 332 | /* ELVSS off */ |
| 344 | 333 | 0xb1, 0x0a, |
| 345 | 334 | |
| 346 | 335 | ENDDEF, 0x0000 |
| 347 | 336 | }; |
| 348 | 337 | |
| 349 | −static const unsigned short SEQ_STAND_BY_OFF[] = { | |
| 338 | +static const unsigned short seq_stand_by_off[] = { | |
| 350 | 339 | 0x11, COMMAND_ONLY, |
| 351 | 340 | |
| 352 | 341 | ENDDEF, 0x0000 |
| 353 | 342 | }; |
| 354 | 343 | |
| 355 | −static const unsigned short SEQ_STAND_BY_ON[] = { | |
| 344 | +static const unsigned short seq_stand_by_on[] = { | |
| 356 | 345 | 0x10, COMMAND_ONLY, |
| 357 | 346 | |
| 358 | 347 | ENDDEF, 0x0000 |
| 359 | 348 | }; |
| 360 | 349 | |
| 361 | −static const unsigned short SEQ_DISPLAY_ON[] = { | |
| 350 | +static const unsigned short seq_display_on[] = { | |
| 362 | 351 | 0x29, COMMAND_ONLY, |
| 363 | 352 | |
| 364 | 353 | ENDDEF, 0x0000 |
| @@ -406,8 +395,9 @@ static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, · 41 unmodified lines | ||
| 406 | 395 | ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); |
| 407 | 396 | if (ret) |
| 408 | 397 | break; |
| 409 | − } else | |
| 410 | − udelay(wbuf[i+1]*1000); | |
| 398 | + } else { | |
| 399 | + msleep(wbuf[i+1]); | |
| 400 | + } | |
| 411 | 401 | i += 2; |
| 412 | 402 | } |
| 413 | 403 | |
| @@ -457,12 +447,12 @@ static int s6e63m0_ldi_init(struct s6e63m0 *lcd) · 43 unmodified lines | ||
| 457 | 447 | { |
| 458 | 448 | int ret, i; |
| 459 | 449 | const unsigned short *init_seq[] = { |
| 460 | − SEQ_PANEL_CONDITION_SET, | |
| 461 | − SEQ_DISPLAY_CONDITION_SET, | |
| 462 | − SEQ_GAMMA_SETTING, | |
| 463 | − SEQ_ETC_CONDITION_SET, | |
| 464 | − SEQ_ACL_ON, | |
| 465 | − SEQ_ELVSS_ON, | |
| 450 | + seq_panel_condition_set, | |
| 451 | + seq_display_condition_set, | |
| 452 | + seq_gamma_setting, | |
| 453 | + seq_etc_condition_set, | |
| 454 | + seq_acl_on, | |
| 455 | + seq_elvss_on, | |
| 466 | 456 | }; |
| 467 | 457 | |
| 468 | 458 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { |
| @@ -478,8 +468,8 @@ static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) · 9 unmodified lines | ||
| 478 | 468 | { |
| 479 | 469 | int ret = 0, i; |
| 480 | 470 | const unsigned short *enable_seq[] = { |
| 481 | − SEQ_STAND_BY_OFF, | |
| 482 | − SEQ_DISPLAY_ON, | |
| 471 | + seq_stand_by_off, | |
| 472 | + seq_display_on, | |
| 483 | 473 | }; |
| 484 | 474 | |
| 485 | 475 | for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { |
| @@ -495,43 +485,39 @@ static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) · 9 unmodified lines | ||
| 495 | 485 | { |
| 496 | 486 | int ret; |
| 497 | 487 | |
| 498 | − ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON); | |
| 488 | + ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on); | |
| 499 | 489 | |
| 500 | 490 | return ret; |
| 501 | 491 | } |
| 502 | 492 | |
| 493 | +static int s6e63m0_power_is_on(int power) | |
| 494 | +{ | |
| 495 | + return power <= FB_BLANK_NORMAL; | |
| 496 | +} | |
| 497 | + | |
| 503 | 498 | static int s6e63m0_power_on(struct s6e63m0 *lcd) |
| 504 | 499 | { |
| 505 | 500 | int ret = 0; |
| 506 | − struct lcd_platform_data *pd = NULL; | |
| 507 | − struct backlight_device *bd = NULL; | |
| 501 | + struct lcd_platform_data *pd; | |
| 502 | + struct backlight_device *bd; | |
| 508 | 503 | |
| 509 | 504 | pd = lcd->lcd_pd; |
| 510 | − if (!pd) { | |
| 511 | − dev_err(lcd->dev, "platform data is NULL.\n"); | |
| 512 | − return -EFAULT; | |
| 513 | − } | |
| 514 | − | |
| 515 | 505 | bd = lcd->bd; |
| 516 | − if (!bd) { | |
| 517 | − dev_err(lcd->dev, "backlight device is NULL.\n"); | |
| 518 | − return -EFAULT; | |
| 519 | − } | |
| 520 | 506 | |
| 521 | 507 | if (!pd->power_on) { |
| 522 | 508 | dev_err(lcd->dev, "power_on is NULL.\n"); |
| 523 | − return -EFAULT; | |
| 509 | + return -EINVAL; | |
| 524 | 510 | } else { |
| 525 | 511 | pd->power_on(lcd->ld, 1); |
| 526 | − mdelay(pd->power_on_delay); | |
| 512 | + msleep(pd->power_on_delay); | |
| 527 | 513 | } |
| 528 | 514 | |
| 529 | 515 | if (!pd->reset) { |
| 530 | 516 | dev_err(lcd->dev, "reset is NULL.\n"); |
| 531 | − return -EFAULT; | |
| 517 | + return -EINVAL; | |
| 532 | 518 | } else { |
| 533 | 519 | pd->reset(lcd->ld); |
| 534 | − mdelay(pd->reset_delay); | |
| 520 | + msleep(pd->reset_delay); | |
| 535 | 521 | } |
| 536 | 522 | |
| 537 | 523 | ret = s6e63m0_ldi_init(lcd); |
| @@ -558,14 +544,10 @@ static int s6e63m0_power_on(struct s6e63m0 *lcd) · 20 unmodified lines | ||
| 558 | 544 | |
| 559 | 545 | static int s6e63m0_power_off(struct s6e63m0 *lcd) |
| 560 | 546 | { |
| 561 | − int ret = 0; | |
| 562 | − struct lcd_platform_data *pd = NULL; | |
| 547 | + int ret; | |
| 548 | + struct lcd_platform_data *pd; | |
| 563 | 549 | |
| 564 | 550 | pd = lcd->lcd_pd; |
| 565 | − if (!pd) { | |
| 566 | − dev_err(lcd->dev, "platform data is NULL.\n"); | |
| 567 | − return -EFAULT; | |
| 568 | − } | |
| 569 | 551 | |
| 570 | 552 | ret = s6e63m0_ldi_disable(lcd); |
| 571 | 553 | if (ret) { |
| @@ -573,13 +555,9 @@ static int s6e63m0_power_off(struct s6e63m0 *lcd) · 1 unmodified line | ||
| 573 | 555 | return -EIO; |
| 574 | 556 | } |
| 575 | 557 | |
| 576 | − mdelay(pd->power_off_delay); | |
| 558 | + msleep(pd->power_off_delay); | |
| 577 | 559 | |
| 578 | − if (!pd->power_on) { | |
| 579 | − dev_err(lcd->dev, "power_on is NULL.\n"); | |
| 580 | − return -EFAULT; | |
| 581 | − } else | |
| 582 | − pd->power_on(lcd->ld, 0); | |
| 560 | + pd->power_on(lcd->ld, 0); | |
| 583 | 561 | |
| 584 | 562 | return 0; |
| 585 | 563 | } |
| @@ -588,9 +566,9 @@ static int s6e63m0_power(struct s6e63m0 *lcd, int power) · 2 unmodified lines | ||
| 588 | 566 | { |
| 589 | 567 | int ret = 0; |
| 590 | 568 | |
| 591 | − if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) | |
| 569 | + if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power)) | |
| 592 | 570 | ret = s6e63m0_power_on(lcd); |
| 593 | − else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) | |
| 571 | + else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power)) | |
| 594 | 572 | ret = s6e63m0_power_off(lcd); |
| 595 | 573 | |
| 596 | 574 | if (!ret) |
| @@ -760,7 +738,7 @@ static int s6e63m0_probe(struct spi_device *spi) · 163 unmodified lines | ||
| 760 | 738 | lcd->lcd_pd = spi->dev.platform_data; |
| 761 | 739 | if (!lcd->lcd_pd) { |
| 762 | 740 | dev_err(&spi->dev, "platform data is NULL.\n"); |
| 763 | − return -EFAULT; | |
| 741 | + return -EINVAL; | |
| 764 | 742 | } |
| 765 | 743 | |
| 766 | 744 | ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); |
| @@ -788,7 +766,7 @@ static int s6e63m0_probe(struct spi_device *spi) · 21 unmodified lines | ||
| 788 | 766 | * know that. |
| 789 | 767 | */ |
| 790 | 768 | lcd->gamma_table_count = |
| 791 | − sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int)); | |
| 769 | + sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *)); | |
| 792 | 770 | |
| 793 | 771 | ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); |
| 794 | 772 | if (ret < 0) |
| @@ -811,10 +789,11 @@ static int s6e63m0_probe(struct spi_device *spi) · 16 unmodified lines | ||
| 811 | 789 | lcd->power = FB_BLANK_POWERDOWN; |
| 812 | 790 | |
| 813 | 791 | s6e63m0_power(lcd, FB_BLANK_UNBLANK); |
| 814 | − } else | |
| 792 | + } else { | |
| 815 | 793 | lcd->power = FB_BLANK_UNBLANK; |
| 794 | + } | |
| 816 | 795 | |
| 817 | − dev_set_drvdata(&spi->dev, lcd); | |
| 796 | + spi_set_drvdata(spi, lcd); | |
| 818 | 797 | |
| 819 | 798 | dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); |
| 820 | 799 | |
| @@ -827,7 +806,7 @@ out_lcd_unregister: · 6 unmodified lines | ||
| 827 | 806 | |
| 828 | 807 | static int s6e63m0_remove(struct spi_device *spi) |
| 829 | 808 | { |
| 830 | − struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | |
| 809 | + struct s6e63m0 *lcd = spi_get_drvdata(spi); | |
| 831 | 810 | |
| 832 | 811 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); |
| 833 | 812 | device_remove_file(&spi->dev, &dev_attr_gamma_table); |
| @@ -839,44 +818,26 @@ static int s6e63m0_remove(struct spi_device *spi) · 5 unmodified lines | ||
| 839 | 818 | } |
| 840 | 819 | |
| 841 | 820 | #if defined(CONFIG_PM) |
| 842 | −static unsigned int before_power; | |
| 843 | − | |
| 844 | 821 | static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) |
| 845 | 822 | { |
| 846 | − int ret = 0; | |
| 847 | − struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | |
| 823 | + struct s6e63m0 *lcd = spi_get_drvdata(spi); | |
| 848 | 824 | |
| 849 | 825 | dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); |
| 850 | 826 | |
| 851 | − before_power = lcd->power; | |
| 852 | − | |
| 853 | 827 | /* |
| 854 | 828 | * when lcd panel is suspend, lcd panel becomes off |
| 855 | 829 | * regardless of status. |
| 856 | 830 | */ |
| 857 | − ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | |
| 858 | − | |
| 859 | − return ret; | |
| 831 | + return s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | |
| 860 | 832 | } |
| 861 | 833 | |
| 862 | 834 | static int s6e63m0_resume(struct spi_device *spi) |
| 863 | 835 | { |
| 864 | − int ret = 0; | |
| 865 | − struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | |
| 866 | − | |
| 867 | − /* | |
| 868 | − * after suspended, if lcd panel status is FB_BLANK_UNBLANK | |
| 869 | − * (at that time, before_power is FB_BLANK_UNBLANK) then | |
| 870 | − * it changes that status to FB_BLANK_POWERDOWN to get lcd on. | |
| 871 | − */ | |
| 872 | − if (before_power == FB_BLANK_UNBLANK) | |
| 873 | − lcd->power = FB_BLANK_POWERDOWN; | |
| 836 | + struct s6e63m0 *lcd = spi_get_drvdata(spi); | |
| 874 | 837 | |
| 875 | − dev_dbg(&spi->dev, "before_power = %d\n", before_power); | |
| 838 | + lcd->power = FB_BLANK_POWERDOWN; | |
| 876 | 839 | |
| 877 | − ret = s6e63m0_power(lcd, before_power); | |
| 878 | − | |
| 879 | − return ret; | |
| 840 | + return s6e63m0_power(lcd, FB_BLANK_UNBLANK); | |
| 880 | 841 | } |
| 881 | 842 | #else |
| 882 | 843 | #define s6e63m0_suspend NULL |
| @@ -886,7 +847,7 @@ static int s6e63m0_resume(struct spi_device *spi) · 3 unmodified lines | ||
| 886 | 847 | /* Power down all displays on reboot, poweroff or halt. */ |
| 887 | 848 | static void s6e63m0_shutdown(struct spi_device *spi) |
| 888 | 849 | { |
| 889 | − struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | |
| 850 | + struct s6e63m0 *lcd = spi_get_drvdata(spi); | |
| 890 | 851 | |
| 891 | 852 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); |
| 892 | 853 | } |
| @@ -390,7 +390,7 @@ static int tdo24m_probe(struct spi_device *spi) · 389 unmodified lines | ||
| 390 | 390 | if (IS_ERR(lcd->lcd_dev)) |
| 391 | 391 | return PTR_ERR(lcd->lcd_dev); |
| 392 | 392 | |
| 393 | − dev_set_drvdata(&spi->dev, lcd); | |
| 393 | + spi_set_drvdata(spi, lcd); | |
| 394 | 394 | err = tdo24m_power(lcd, FB_BLANK_UNBLANK); |
| 395 | 395 | if (err) |
| 396 | 396 | goto out_unregister; |
| @@ -404,7 +404,7 @@ out_unregister: · 7 unmodified lines | ||
| 404 | 404 | |
| 405 | 405 | static int tdo24m_remove(struct spi_device *spi) |
| 406 | 406 | { |
| 407 | − struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | |
| 407 | + struct tdo24m *lcd = spi_get_drvdata(spi); | |
| 408 | 408 | |
| 409 | 409 | tdo24m_power(lcd, FB_BLANK_POWERDOWN); |
| 410 | 410 | lcd_device_unregister(lcd->lcd_dev); |
| @@ -415,14 +415,14 @@ static int tdo24m_remove(struct spi_device *spi) · 4 unmodified lines | ||
| 415 | 415 | #ifdef CONFIG_PM |
| 416 | 416 | static int tdo24m_suspend(struct spi_device *spi, pm_message_t state) |
| 417 | 417 | { |
| 418 | − struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | |
| 418 | + struct tdo24m *lcd = spi_get_drvdata(spi); | |
| 419 | 419 | |
| 420 | 420 | return tdo24m_power(lcd, FB_BLANK_POWERDOWN); |
| 421 | 421 | } |
| 422 | 422 | |
| 423 | 423 | static int tdo24m_resume(struct spi_device *spi) |
| 424 | 424 | { |
| 425 | − struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | |
| 425 | + struct tdo24m *lcd = spi_get_drvdata(spi); | |
| 426 | 426 | |
| 427 | 427 | return tdo24m_power(lcd, FB_BLANK_UNBLANK); |
| 428 | 428 | } |
| @@ -434,7 +434,7 @@ static int tdo24m_resume(struct spi_device *spi) · 5 unmodified lines | ||
| 434 | 434 | /* Power down all displays on reboot, poweroff or halt */ |
| 435 | 435 | static void tdo24m_shutdown(struct spi_device *spi) |
| 436 | 436 | { |
| 437 | − struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | |
| 437 | + struct tdo24m *lcd = spi_get_drvdata(spi); | |
| 438 | 438 | |
| 439 | 439 | tdo24m_power(lcd, FB_BLANK_POWERDOWN); |
| 440 | 440 | } |
| @@ -54,7 +54,7 @@ static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness) · 53 unmodified lines | ||
| 54 | 54 | static int tosa_bl_update_status(struct backlight_device *dev) |
| 55 | 55 | { |
| 56 | 56 | struct backlight_properties *props = &dev->props; |
| 57 | − struct tosa_bl_data *data = dev_get_drvdata(&dev->dev); | |
| 57 | + struct tosa_bl_data *data = bl_get_data(dev); | |
| 58 | 58 | int power = max(props->power, props->fb_blank); |
| 59 | 59 | int brightness = props->brightness; |
| 60 | 60 | |
| @@ -193,7 +193,7 @@ static int tosa_lcd_probe(struct spi_device *spi) · 192 unmodified lines | ||
| 193 | 193 | return ret; |
| 194 | 194 | |
| 195 | 195 | data->spi = spi; |
| 196 | − dev_set_drvdata(&spi->dev, data); | |
| 196 | + spi_set_drvdata(spi, data); | |
| 197 | 197 | |
| 198 | 198 | ret = devm_gpio_request_one(&spi->dev, TOSA_GPIO_TG_ON, |
| 199 | 199 | GPIOF_OUT_INIT_LOW, "tg #pwr"); |
| @@ -220,13 +220,13 @@ static int tosa_lcd_probe(struct spi_device *spi) · 20 unmodified lines | ||
| 220 | 220 | err_register: |
| 221 | 221 | tosa_lcd_tg_off(data); |
| 222 | 222 | err_gpio_tg: |
| 223 | − dev_set_drvdata(&spi->dev, NULL); | |
| 223 | + spi_set_drvdata(spi, NULL); | |
| 224 | 224 | return ret; |
| 225 | 225 | } |
| 226 | 226 | |
| 227 | 227 | static int tosa_lcd_remove(struct spi_device *spi) |
| 228 | 228 | { |
| 229 | − struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); | |
| 229 | + struct tosa_lcd_data *data = spi_get_drvdata(spi); | |
| 230 | 230 | |
| 231 | 231 | lcd_device_unregister(data->lcd); |
| 232 | 232 | |
| @@ -235,7 +235,7 @@ static int tosa_lcd_remove(struct spi_device *spi) · 2 unmodified lines | ||
| 235 | 235 | |
| 236 | 236 | tosa_lcd_tg_off(data); |
| 237 | 237 | |
| 238 | − dev_set_drvdata(&spi->dev, NULL); | |
| 238 | + spi_set_drvdata(spi, NULL); | |
| 239 | 239 | |
| 240 | 240 | return 0; |
| 241 | 241 | } |
| @@ -243,7 +243,7 @@ static int tosa_lcd_remove(struct spi_device *spi) · 1 unmodified line | ||
| 243 | 243 | #ifdef CONFIG_PM |
| 244 | 244 | static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state) |
| 245 | 245 | { |
| 246 | − struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); | |
| 246 | + struct tosa_lcd_data *data = spi_get_drvdata(spi); | |
| 247 | 247 | |
| 248 | 248 | tosa_lcd_tg_off(data); |
| 249 | 249 | |
| @@ -252,7 +252,7 @@ static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state) · 2 unmodified lines | ||
| 252 | 252 | |
| 253 | 253 | static int tosa_lcd_resume(struct spi_device *spi) |
| 254 | 254 | { |
| 255 | − struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); | |
| 255 | + struct tosa_lcd_data *data = spi_get_drvdata(spi); | |
| 256 | 256 | |
| 257 | 257 | tosa_lcd_tg_init(data); |
| 258 | 258 | if (POWER_IS_ON(data->lcd_power)) |
| @@ -208,12 +208,11 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd, · 207 unmodified lines | ||
| 208 | 208 | #ifdef CONFIG_PM |
| 209 | 209 | static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state) |
| 210 | 210 | { |
| 211 | − return ili9320_suspend(dev_get_drvdata(&spi->dev), state); | |
| 211 | + return ili9320_suspend(spi_get_drvdata(spi), state); | |
| 212 | 212 | } |
| 213 | − | |
| 214 | 213 | static int vgg2432a4_resume(struct spi_device *spi) |
| 215 | 214 | { |
| 216 | − return ili9320_resume(dev_get_drvdata(&spi->dev)); | |
| 215 | + return ili9320_resume(spi_get_drvdata(spi)); | |
| 217 | 216 | } |
| 218 | 217 | #else |
| 219 | 218 | #define vgg2432a4_suspend NULL |
| @@ -242,12 +241,12 @@ static int vgg2432a4_probe(struct spi_device *spi) · 22 unmodified lines | ||
| 242 | 241 | |
| 243 | 242 | static int vgg2432a4_remove(struct spi_device *spi) |
| 244 | 243 | { |
| 245 | − return ili9320_remove(dev_get_drvdata(&spi->dev)); | |
| 244 | + return ili9320_remove(spi_get_drvdata(spi)); | |
| 246 | 245 | } |
| 247 | 246 | |
| 248 | 247 | static void vgg2432a4_shutdown(struct spi_device *spi) |
| 249 | 248 | { |
| 250 | − ili9320_shutdown(dev_get_drvdata(&spi->dev)); | |
| 249 | + ili9320_shutdown(spi_get_drvdata(spi)); | |
| 251 | 250 | } |
| 252 | 251 | |
| 253 | 252 | static struct spi_driver vgg2432a4_driver = { |
| @@ -1242,8 +1242,16 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, · 1241 unmodified lines | ||
| 1242 | 1242 | if (!height || !width) |
| 1243 | 1243 | return; |
| 1244 | 1244 | |
| 1245 | − if (sy < vc->vc_top && vc->vc_top == logo_lines) | |
| 1245 | + if (sy < vc->vc_top && vc->vc_top == logo_lines) { | |
| 1246 | 1246 | vc->vc_top = 0; |
| 1247 | + /* | |
| 1248 | + * If the font dimensions are not an integral of the display | |
| 1249 | + * dimensions then the ops->clear below won't end up clearing | |
| 1250 | + * the margins. Call clear_margins here in case the logo | |
| 1251 | + * bitmap stretched into the margin area. | |
| 1252 | + */ | |
| 1253 | + fbcon_clear_margins(vc, 0); | |
| 1254 | + } | |
| 1247 | 1255 | |
| 1248 | 1256 | /* Split blits that cross physical y_wrap boundary */ |
| 1249 | 1257 | |
| @@ -965,10 +965,11 @@ static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev) · 964 unmodified lines | ||
| 965 | 965 | |
| 966 | 966 | static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) |
| 967 | 967 | { |
| 968 | − struct device_node *dp_phy_node; | |
| 968 | + struct device_node *dp_phy_node = of_node_get(dp->dev->of_node); | |
| 969 | 969 | u32 phy_base; |
| 970 | + int ret = 0; | |
| 970 | 971 | |
| 971 | − dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy"); | |
| 972 | + dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); | |
| 972 | 973 | if (!dp_phy_node) { |
| 973 | 974 | dev_err(dp->dev, "could not find dptx-phy node\n"); |
| 974 | 975 | return -ENODEV; |
| @@ -976,22 +977,28 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) · 1 unmodified line | ||
| 976 | 977 | |
| 977 | 978 | if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { |
| 978 | 979 | dev_err(dp->dev, "faild to get reg for dptx-phy\n"); |
| 979 | − return -EINVAL; | |
| 980 | + ret = -EINVAL; | |
| 981 | + goto err; | |
| 980 | 982 | } |
| 981 | 983 | |
| 982 | 984 | if (of_property_read_u32(dp_phy_node, "samsung,enable-mask", |
| 983 | 985 | &dp->enable_mask)) { |
| 984 | 986 | dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n"); |
| 985 | − return -EINVAL; | |
| 987 | + ret = -EINVAL; | |
| 988 | + goto err; | |
| 986 | 989 | } |
| 987 | 990 | |
| 988 | 991 | dp->phy_addr = ioremap(phy_base, SZ_4); |
| 989 | 992 | if (!dp->phy_addr) { |
| 990 | 993 | dev_err(dp->dev, "failed to ioremap dp-phy\n"); |
| 991 | − return -ENOMEM; | |
| 994 | + ret = -ENOMEM; | |
| 995 | + goto err; | |
| 992 | 996 | } |
| 993 | 997 | |
| 994 | − return 0; | |
| 998 | +err: | |
| 999 | + of_node_put(dp_phy_node); | |
| 1000 | + | |
| 1001 | + return ret; | |
| 995 | 1002 | } |
| 996 | 1003 | |
| 997 | 1004 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) |
| @@ -1117,8 +1124,6 @@ static int exynos_dp_remove(struct platform_device *pdev) · 119 unmodified lines | ||
| 1117 | 1124 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; |
| 1118 | 1125 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); |
| 1119 | 1126 | |
| 1120 | − disable_irq(dp->irq); | |
| 1121 | − | |
| 1122 | 1127 | flush_work(&dp->hotplug_work); |
| 1123 | 1128 | |
| 1124 | 1129 | if (pdev->dev.of_node) { |
| @@ -1141,6 +1146,8 @@ static int exynos_dp_suspend(struct device *dev) · 16 unmodified lines | ||
| 1141 | 1146 | struct exynos_dp_platdata *pdata = dev->platform_data; |
| 1142 | 1147 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 1143 | 1148 | |
| 1149 | + disable_irq(dp->irq); | |
| 1150 | + | |
| 1144 | 1151 | flush_work(&dp->hotplug_work); |
| 1145 | 1152 | |
| 1146 | 1153 | if (dev->of_node) { |
| @@ -338,7 +338,8 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) · 337 unmodified lines | ||
| 338 | 338 | struct mipi_dsim_ddi *dsim_ddi; |
| 339 | 339 | int ret = -EINVAL; |
| 340 | 340 | |
| 341 | − dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); | |
| 341 | + dsim = devm_kzalloc(&pdev->dev, sizeof(struct mipi_dsim_device), | |
| 342 | + GFP_KERNEL); | |
| 342 | 343 | if (!dsim) { |
| 343 | 344 | dev_err(&pdev->dev, "failed to allocate dsim object.\n"); |
| 344 | 345 | return -ENOMEM; |
| @@ -352,13 +353,13 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) · 7 unmodified lines | ||
| 352 | 353 | dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd; |
| 353 | 354 | if (dsim_pd == NULL) { |
| 354 | 355 | dev_err(&pdev->dev, "failed to get platform data for dsim.\n"); |
| 355 | − goto err_clock_get; | |
| 356 | + return -EINVAL; | |
| 356 | 357 | } |
| 357 | 358 | /* get mipi_dsim_config. */ |
| 358 | 359 | dsim_config = dsim_pd->dsim_config; |
| 359 | 360 | if (dsim_config == NULL) { |
| 360 | 361 | dev_err(&pdev->dev, "failed to get dsim config data.\n"); |
| 361 | − goto err_clock_get; | |
| 362 | + return -EINVAL; | |
| 362 | 363 | } |
| 363 | 364 | |
| 364 | 365 | dsim->dsim_config = dsim_config; |
| @@ -366,41 +367,28 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 366 | 367 | |
| 367 | 368 | mutex_init(&dsim->lock); |
| 368 | 369 | |
| 369 | − ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies); | |
| 370 | + ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), | |
| 371 | + supplies); | |
| 370 | 372 | if (ret) { |
| 371 | 373 | dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret); |
| 372 | − goto err_clock_get; | |
| 374 | + return ret; | |
| 373 | 375 | } |
| 374 | 376 | |
| 375 | − dsim->clock = clk_get(&pdev->dev, "dsim0"); | |
| 377 | + dsim->clock = devm_clk_get(&pdev->dev, "dsim0"); | |
| 376 | 378 | if (IS_ERR(dsim->clock)) { |
| 377 | 379 | dev_err(&pdev->dev, "failed to get dsim clock source\n"); |
| 378 | − ret = -ENODEV; | |
| 379 | − goto err_clock_get; | |
| 380 | + return -ENODEV; | |
| 380 | 381 | } |
| 381 | 382 | |
| 382 | 383 | clk_enable(dsim->clock); |
| 383 | 384 | |
| 384 | 385 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 385 | − if (!res) { | |
| 386 | − dev_err(&pdev->dev, "failed to get io memory region\n"); | |
| 387 | − ret = -ENODEV; | |
| 388 | − goto err_platform_get; | |
| 389 | − } | |
| 390 | − | |
| 391 | − dsim->res = request_mem_region(res->start, resource_size(res), | |
| 392 | − dev_name(&pdev->dev)); | |
| 393 | − if (!dsim->res) { | |
| 394 | − dev_err(&pdev->dev, "failed to request io memory region\n"); | |
| 395 | − ret = -ENOMEM; | |
| 396 | − goto err_mem_region; | |
| 397 | − } | |
| 398 | 386 | |
| 399 | − dsim->reg_base = ioremap(res->start, resource_size(res)); | |
| 387 | + dsim->reg_base = devm_request_and_ioremap(&pdev->dev, res); | |
| 400 | 388 | if (!dsim->reg_base) { |
| 401 | 389 | dev_err(&pdev->dev, "failed to remap io region\n"); |
| 402 | 390 | ret = -ENOMEM; |
| 403 | − goto err_ioremap; | |
| 391 | + goto error; | |
| 404 | 392 | } |
| 405 | 393 | |
| 406 | 394 | mutex_init(&dsim->lock); |
| @@ -410,26 +398,27 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 410 | 398 | if (!dsim_ddi) { |
| 411 | 399 | dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); |
| 412 | 400 | ret = -EINVAL; |
| 413 | − goto err_bind; | |
| 401 | + goto error; | |
| 414 | 402 | } |
| 415 | 403 | |
| 416 | 404 | dsim->irq = platform_get_irq(pdev, 0); |
| 417 | − if (dsim->irq < 0) { | |
| 405 | + if (IS_ERR_VALUE(dsim->irq)) { | |
| 418 | 406 | dev_err(&pdev->dev, "failed to request dsim irq resource\n"); |
| 419 | 407 | ret = -EINVAL; |
| 420 | − goto err_platform_get_irq; | |
| 408 | + goto error; | |
| 421 | 409 | } |
| 422 | 410 | |
| 423 | 411 | init_completion(&dsim_wr_comp); |
| 424 | 412 | init_completion(&dsim_rd_comp); |
| 425 | 413 | platform_set_drvdata(pdev, dsim); |
| 426 | 414 | |
| 427 | − ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler, | |
| 415 | + ret = devm_request_irq(&pdev->dev, dsim->irq, | |
| 416 | + exynos_mipi_dsi_interrupt_handler, | |
| 428 | 417 | IRQF_SHARED, dev_name(&pdev->dev), dsim); |
| 429 | 418 | if (ret != 0) { |
| 430 | 419 | dev_err(&pdev->dev, "failed to request dsim irq\n"); |
| 431 | 420 | ret = -EINVAL; |
| 432 | − goto err_bind; | |
| 421 | + goto error; | |
| 433 | 422 | } |
| 434 | 423 | |
| 435 | 424 | /* enable interrupts */ |
| @@ -471,22 +460,8 @@ done: · 35 unmodified lines | ||
| 471 | 460 | |
| 472 | 461 | return 0; |
| 473 | 462 | |
| 474 | −err_bind: | |
| 475 | − iounmap(dsim->reg_base); | |
| 476 | − | |
| 477 | −err_ioremap: | |
| 478 | − release_mem_region(dsim->res->start, resource_size(dsim->res)); | |
| 479 | − | |
| 480 | −err_mem_region: | |
| 481 | − release_resource(dsim->res); | |
| 482 | − | |
| 483 | −err_platform_get: | |
| 463 | +error: | |
| 484 | 464 | clk_disable(dsim->clock); |
| 485 | − clk_put(dsim->clock); | |
| 486 | −err_clock_get: | |
| 487 | − kfree(dsim); | |
| 488 | − | |
| 489 | −err_platform_get_irq: | |
| 490 | 465 | return ret; |
| 491 | 466 | } |
| 492 | 467 | |
| @@ -496,13 +471,7 @@ static int exynos_mipi_dsi_remove(struct platform_device *pdev) · 3 unmodified lines | ||
| 496 | 471 | struct mipi_dsim_ddi *dsim_ddi, *next; |
| 497 | 472 | struct mipi_dsim_lcd_driver *dsim_lcd_drv; |
| 498 | 473 | |
| 499 | − iounmap(dsim->reg_base); | |
| 500 | − | |
| 501 | 474 | clk_disable(dsim->clock); |
| 502 | − clk_put(dsim->clock); | |
| 503 | − | |
| 504 | − release_resource(dsim->res); | |
| 505 | − release_mem_region(dsim->res->start, resource_size(dsim->res)); | |
| 506 | 475 | |
| 507 | 476 | list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { |
| 508 | 477 | if (dsim_ddi) { |
| @@ -518,9 +487,6 @@ static int exynos_mipi_dsi_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 518 | 487 | } |
| 519 | 488 | } |
| 520 | 489 | |
| 521 | − regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | |
| 522 | − kfree(dsim); | |
| 523 | − | |
| 524 | 490 | return 0; |
| 525 | 491 | } |
| 526 | 492 | |
| @@ -776,7 +776,7 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) · 775 unmodified lines | ||
| 776 | 776 | int ret; |
| 777 | 777 | u8 mtp_id[3] = {0, }; |
| 778 | 778 | |
| 779 | − lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL); | |
| 779 | + lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct s6e8ax0), GFP_KERNEL); | |
| 780 | 780 | if (!lcd) { |
| 781 | 781 | dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n"); |
| 782 | 782 | return -ENOMEM; |
| @@ -788,18 +788,17 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) · 5 unmodified lines | ||
| 788 | 788 | |
| 789 | 789 | mutex_init(&lcd->lock); |
| 790 | 790 | |
| 791 | − ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); | |
| 791 | + ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); | |
| 792 | 792 | if (ret) { |
| 793 | 793 | dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); |
| 794 | − goto err_lcd_register; | |
| 794 | + return ret; | |
| 795 | 795 | } |
| 796 | 796 | |
| 797 | 797 | lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd, |
| 798 | 798 | &s6e8ax0_lcd_ops); |
| 799 | 799 | if (IS_ERR(lcd->ld)) { |
| 800 | 800 | dev_err(lcd->dev, "failed to register lcd ops.\n"); |
| 801 | − ret = PTR_ERR(lcd->ld); | |
| 802 | − goto err_lcd_register; | |
| 801 | + return PTR_ERR(lcd->ld); | |
| 803 | 802 | } |
| 804 | 803 | |
| 805 | 804 | lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd, |
| @@ -838,11 +837,6 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) · 32 unmodified lines | ||
| 838 | 837 | |
| 839 | 838 | err_backlight_register: |
| 840 | 839 | lcd_device_unregister(lcd->ld); |
| 841 | − | |
| 842 | −err_lcd_register: | |
| 843 | − regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | |
| 844 | − kfree(lcd); | |
| 845 | − | |
| 846 | 840 | return ret; |
| 847 | 841 | } |
| 848 | 842 | |
| @@ -0,0 +1,318 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2007 Google, Inc. | |
| 3 | + * Copyright (C) 2012 Intel, Inc. | |
| 4 | + * | |
| 5 | + * This software is licensed under the terms of the GNU General Public | |
| 6 | + * License version 2, as published by the Free Software Foundation, and | |
| 7 | + * may be copied, distributed, and modified under those terms. | |
| 8 | + * | |
| 9 | + * This program is distributed in the hope that it will be useful, | |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + * GNU General Public License for more details. | |
| 13 | + * | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/dma-mapping.h> | |
| 19 | +#include <linux/errno.h> | |
| 20 | +#include <linux/string.h> | |
| 21 | +#include <linux/slab.h> | |
| 22 | +#include <linux/delay.h> | |
| 23 | +#include <linux/mm.h> | |
| 24 | +#include <linux/fb.h> | |
| 25 | +#include <linux/init.h> | |
| 26 | +#include <linux/interrupt.h> | |
| 27 | +#include <linux/ioport.h> | |
| 28 | +#include <linux/platform_device.h> | |
| 29 | + | |
| 30 | +enum { | |
| 31 | + FB_GET_WIDTH = 0x00, | |
| 32 | + FB_GET_HEIGHT = 0x04, | |
| 33 | + FB_INT_STATUS = 0x08, | |
| 34 | + FB_INT_ENABLE = 0x0c, | |
| 35 | + FB_SET_BASE = 0x10, | |
| 36 | + FB_SET_ROTATION = 0x14, | |
| 37 | + FB_SET_BLANK = 0x18, | |
| 38 | + FB_GET_PHYS_WIDTH = 0x1c, | |
| 39 | + FB_GET_PHYS_HEIGHT = 0x20, | |
| 40 | + | |
| 41 | + FB_INT_VSYNC = 1U << 0, | |
| 42 | + FB_INT_BASE_UPDATE_DONE = 1U << 1 | |
| 43 | +}; | |
| 44 | + | |
| 45 | +struct goldfish_fb { | |
| 46 | + void __iomem *reg_base; | |
| 47 | + int irq; | |
| 48 | + spinlock_t lock; | |
| 49 | + wait_queue_head_t wait; | |
| 50 | + int base_update_count; | |
| 51 | + int rotation; | |
| 52 | + struct fb_info fb; | |
| 53 | + u32 cmap[16]; | |
| 54 | +}; | |
| 55 | + | |
| 56 | +static irqreturn_t goldfish_fb_interrupt(int irq, void *dev_id) | |
| 57 | +{ | |
| 58 | + unsigned long irq_flags; | |
| 59 | + struct goldfish_fb *fb = dev_id; | |
| 60 | + u32 status; | |
| 61 | + | |
| 62 | + spin_lock_irqsave(&fb->lock, irq_flags); | |
| 63 | + status = readl(fb->reg_base + FB_INT_STATUS); | |
| 64 | + if (status & FB_INT_BASE_UPDATE_DONE) { | |
| 65 | + fb->base_update_count++; | |
| 66 | + wake_up(&fb->wait); | |
| 67 | + } | |
| 68 | + spin_unlock_irqrestore(&fb->lock, irq_flags); | |
| 69 | + return status ? IRQ_HANDLED : IRQ_NONE; | |
| 70 | +} | |
| 71 | + | |
| 72 | +static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) | |
| 73 | +{ | |
| 74 | + unsigned int mask = (1 << bf->length) - 1; | |
| 75 | + | |
| 76 | + return (val >> (16 - bf->length) & mask) << bf->offset; | |
| 77 | +} | |
| 78 | + | |
| 79 | +static int | |
| 80 | +goldfish_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, | |
| 81 | + unsigned int blue, unsigned int transp, struct fb_info *info) | |
| 82 | +{ | |
| 83 | + struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); | |
| 84 | + | |
| 85 | + if (regno < 16) { | |
| 86 | + fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | | |
| 87 | + convert_bitfield(blue, &fb->fb.var.blue) | | |
| 88 | + convert_bitfield(green, &fb->fb.var.green) | | |
| 89 | + convert_bitfield(red, &fb->fb.var.red); | |
| 90 | + return 0; | |
| 91 | + } else { | |
| 92 | + return 1; | |
| 93 | + } | |
| 94 | +} | |
| 95 | + | |
| 96 | +static int goldfish_fb_check_var(struct fb_var_screeninfo *var, | |
| 97 | + struct fb_info *info) | |
| 98 | +{ | |
| 99 | + if ((var->rotate & 1) != (info->var.rotate & 1)) { | |
| 100 | + if ((var->xres != info->var.yres) || | |
| 101 | + (var->yres != info->var.xres) || | |
| 102 | + (var->xres_virtual != info->var.yres) || | |
| 103 | + (var->yres_virtual > info->var.xres * 2) || | |
| 104 | + (var->yres_virtual < info->var.xres)) { | |
| 105 | + return -EINVAL; | |
| 106 | + } | |
| 107 | + } else { | |
| 108 | + if ((var->xres != info->var.xres) || | |
| 109 | + (var->yres != info->var.yres) || | |
| 110 | + (var->xres_virtual != info->var.xres) || | |
| 111 | + (var->yres_virtual > info->var.yres * 2) || | |
| 112 | + (var->yres_virtual < info->var.yres)) { | |
| 113 | + return -EINVAL; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + if ((var->xoffset != info->var.xoffset) || | |
| 117 | + (var->bits_per_pixel != info->var.bits_per_pixel) || | |
| 118 | + (var->grayscale != info->var.grayscale)) { | |
| 119 | + return -EINVAL; | |
| 120 | + } | |
| 121 | + return 0; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static int goldfish_fb_set_par(struct fb_info *info) | |
| 125 | +{ | |
| 126 | + struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); | |
| 127 | + if (fb->rotation != fb->fb.var.rotate) { | |
| 128 | + info->fix.line_length = info->var.xres * 2; | |
| 129 | + fb->rotation = fb->fb.var.rotate; | |
| 130 | + writel(fb->rotation, fb->reg_base + FB_SET_ROTATION); | |
| 131 | + } | |
| 132 | + return 0; | |
| 133 | +} | |
| 134 | + | |
| 135 | + | |
| 136 | +static int goldfish_fb_pan_display(struct fb_var_screeninfo *var, | |
| 137 | + struct fb_info *info) | |
| 138 | +{ | |
| 139 | + unsigned long irq_flags; | |
| 140 | + int base_update_count; | |
| 141 | + struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); | |
| 142 | + | |
| 143 | + spin_lock_irqsave(&fb->lock, irq_flags); | |
| 144 | + base_update_count = fb->base_update_count; | |
| 145 | + writel(fb->fb.fix.smem_start + fb->fb.var.xres * 2 * var->yoffset, | |
| 146 | + fb->reg_base + FB_SET_BASE); | |
| 147 | + spin_unlock_irqrestore(&fb->lock, irq_flags); | |
| 148 | + wait_event_timeout(fb->wait, | |
| 149 | + fb->base_update_count != base_update_count, HZ / 15); | |
| 150 | + if (fb->base_update_count == base_update_count) | |
| 151 | + pr_err("goldfish_fb_pan_display: timeout wating for base update\n"); | |
| 152 | + return 0; | |
| 153 | +} | |
| 154 | + | |
| 155 | +static int goldfish_fb_blank(int blank, struct fb_info *info) | |
| 156 | +{ | |
| 157 | + struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); | |
| 158 | + switch (blank) { | |
| 159 | + case FB_BLANK_NORMAL: | |
| 160 | + writel(1, fb->reg_base + FB_SET_BLANK); | |
| 161 | + break; | |
| 162 | + case FB_BLANK_UNBLANK: | |
| 163 | + writel(0, fb->reg_base + FB_SET_BLANK); | |
| 164 | + break; | |
| 165 | + } | |
| 166 | + return 0; | |
| 167 | +} | |
| 168 | + | |
| 169 | +static struct fb_ops goldfish_fb_ops = { | |
| 170 | + .owner = THIS_MODULE, | |
| 171 | + .fb_check_var = goldfish_fb_check_var, | |
| 172 | + .fb_set_par = goldfish_fb_set_par, | |
| 173 | + .fb_setcolreg = goldfish_fb_setcolreg, | |
| 174 | + .fb_pan_display = goldfish_fb_pan_display, | |
| 175 | + .fb_blank = goldfish_fb_blank, | |
| 176 | + .fb_fillrect = cfb_fillrect, | |
| 177 | + .fb_copyarea = cfb_copyarea, | |
| 178 | + .fb_imageblit = cfb_imageblit, | |
| 179 | +}; | |
| 180 | + | |
| 181 | + | |
| 182 | +static int goldfish_fb_probe(struct platform_device *pdev) | |
| 183 | +{ | |
| 184 | + int ret; | |
| 185 | + struct resource *r; | |
| 186 | + struct goldfish_fb *fb; | |
| 187 | + size_t framesize; | |
| 188 | + u32 width, height; | |
| 189 | + dma_addr_t fbpaddr; | |
| 190 | + | |
| 191 | + fb = kzalloc(sizeof(*fb), GFP_KERNEL); | |
| 192 | + if (fb == NULL) { | |
| 193 | + ret = -ENOMEM; | |
| 194 | + goto err_fb_alloc_failed; | |
| 195 | + } | |
| 196 | + spin_lock_init(&fb->lock); | |
| 197 | + init_waitqueue_head(&fb->wait); | |
| 198 | + platform_set_drvdata(pdev, fb); | |
| 199 | + | |
| 200 | + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 201 | + if (r == NULL) { | |
| 202 | + ret = -ENODEV; | |
| 203 | + goto err_no_io_base; | |
| 204 | + } | |
| 205 | + fb->reg_base = ioremap(r->start, PAGE_SIZE); | |
| 206 | + if (fb->reg_base == NULL) { | |
| 207 | + ret = -ENOMEM; | |
| 208 | + goto err_no_io_base; | |
| 209 | + } | |
| 210 | + | |
| 211 | + fb->irq = platform_get_irq(pdev, 0); | |
| 212 | + if (fb->irq <= 0) { | |
| 213 | + ret = -ENODEV; | |
| 214 | + goto err_no_irq; | |
| 215 | + } | |
| 216 | + | |
| 217 | + width = readl(fb->reg_base + FB_GET_WIDTH); | |
| 218 | + height = readl(fb->reg_base + FB_GET_HEIGHT); | |
| 219 | + | |
| 220 | + fb->fb.fbops = &goldfish_fb_ops; | |
| 221 | + fb->fb.flags = FBINFO_FLAG_DEFAULT; | |
| 222 | + fb->fb.pseudo_palette = fb->cmap; | |
| 223 | + fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; | |
| 224 | + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; | |
| 225 | + fb->fb.fix.line_length = width * 2; | |
| 226 | + fb->fb.fix.accel = FB_ACCEL_NONE; | |
| 227 | + fb->fb.fix.ypanstep = 1; | |
| 228 | + | |
| 229 | + fb->fb.var.xres = width; | |
| 230 | + fb->fb.var.yres = height; | |
| 231 | + fb->fb.var.xres_virtual = width; | |
| 232 | + fb->fb.var.yres_virtual = height * 2; | |
| 233 | + fb->fb.var.bits_per_pixel = 16; | |
| 234 | + fb->fb.var.activate = FB_ACTIVATE_NOW; | |
| 235 | + fb->fb.var.height = readl(fb->reg_base + FB_GET_PHYS_HEIGHT); | |
| 236 | + fb->fb.var.width = readl(fb->reg_base + FB_GET_PHYS_WIDTH); | |
| 237 | + fb->fb.var.pixclock = 10000; | |
| 238 | + | |
| 239 | + fb->fb.var.red.offset = 11; | |
| 240 | + fb->fb.var.red.length = 5; | |
| 241 | + fb->fb.var.green.offset = 5; | |
| 242 | + fb->fb.var.green.length = 6; | |
| 243 | + fb->fb.var.blue.offset = 0; | |
| 244 | + fb->fb.var.blue.length = 5; | |
| 245 | + | |
| 246 | + framesize = width * height * 2 * 2; | |
| 247 | + fb->fb.screen_base = (char __force __iomem *)dma_alloc_coherent( | |
| 248 | + &pdev->dev, framesize, | |
| 249 | + &fbpaddr, GFP_KERNEL); | |
| 250 | + pr_debug("allocating frame buffer %d * %d, got %p\n", | |
| 251 | + width, height, fb->fb.screen_base); | |
| 252 | + if (fb->fb.screen_base == NULL) { | |
| 253 | + ret = -ENOMEM; | |
| 254 | + goto err_alloc_screen_base_failed; | |
| 255 | + } | |
| 256 | + fb->fb.fix.smem_start = fbpaddr; | |
| 257 | + fb->fb.fix.smem_len = framesize; | |
| 258 | + | |
| 259 | + ret = fb_set_var(&fb->fb, &fb->fb.var); | |
| 260 | + if (ret) | |
| 261 | + goto err_fb_set_var_failed; | |
| 262 | + | |
| 263 | + ret = request_irq(fb->irq, goldfish_fb_interrupt, IRQF_SHARED, | |
| 264 | + pdev->name, fb); | |
| 265 | + if (ret) | |
| 266 | + goto err_request_irq_failed; | |
| 267 | + | |
| 268 | + writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB_INT_ENABLE); | |
| 269 | + goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */ | |
| 270 | + | |
| 271 | + ret = register_framebuffer(&fb->fb); | |
| 272 | + if (ret) | |
| 273 | + goto err_register_framebuffer_failed; | |
| 274 | + return 0; | |
| 275 | + | |
| 276 | +err_register_framebuffer_failed: | |
| 277 | + free_irq(fb->irq, fb); | |
| 278 | +err_request_irq_failed: | |
| 279 | +err_fb_set_var_failed: | |
| 280 | + dma_free_coherent(&pdev->dev, framesize, | |
| 281 | + (void *)fb->fb.screen_base, | |
| 282 | + fb->fb.fix.smem_start); | |
| 283 | +err_alloc_screen_base_failed: | |
| 284 | +err_no_irq: | |
| 285 | + iounmap(fb->reg_base); | |
| 286 | +err_no_io_base: | |
| 287 | + kfree(fb); | |
| 288 | +err_fb_alloc_failed: | |
| 289 | + return ret; | |
| 290 | +} | |
| 291 | + | |
| 292 | +static int goldfish_fb_remove(struct platform_device *pdev) | |
| 293 | +{ | |
| 294 | + size_t framesize; | |
| 295 | + struct goldfish_fb *fb = platform_get_drvdata(pdev); | |
| 296 | + | |
| 297 | + framesize = fb->fb.var.xres_virtual * fb->fb.var.yres_virtual * 2; | |
| 298 | + unregister_framebuffer(&fb->fb); | |
| 299 | + free_irq(fb->irq, fb); | |
| 300 | + | |
| 301 | + dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, | |
| 302 | + fb->fb.fix.smem_start); | |
| 303 | + iounmap(fb->reg_base); | |
| 304 | + return 0; | |
| 305 | +} | |
| 306 | + | |
| 307 | + | |
| 308 | +static struct platform_driver goldfish_fb_driver = { | |
| 309 | + .probe = goldfish_fb_probe, | |
| 310 | + .remove = goldfish_fb_remove, | |
| 311 | + .driver = { | |
| 312 | + .name = "goldfish_fb" | |
| 313 | + } | |
| 314 | +}; | |
| 315 | + | |
| 316 | +module_platform_driver(goldfish_fb_driver); | |
| 317 | + | |
| 318 | +MODULE_LICENSE("GPL v2"); | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +menuconfig MMP_DISP | |
| 2 | + tristate "Marvell MMP Display Subsystem support" | |
| 3 | + depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988 | |
| 4 | + help | |
| 5 | + Marvell Display Subsystem support. | |
| 6 | + | |
| 7 | +if MMP_DISP | |
| 8 | +source "drivers/video/mmp/hw/Kconfig" | |
| 9 | +source "drivers/video/mmp/panel/Kconfig" | |
| 10 | +source "drivers/video/mmp/fb/Kconfig" | |
| 11 | +endif | |
| @@ -0,0 +1 @@ | ||
| 1 | +obj-y += core.o hw/ panel/ fb/ | |
| @@ -0,0 +1,258 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/common.c | |
| 3 | + * This driver is a common framework for Marvell Display Controller | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Zhou Zhu <zzhu3@marvell.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 14 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 16 | + * more details. | |
| 17 | + * | |
| 18 | + * You should have received a copy of the GNU General Public License along with | |
| 19 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 20 | + * | |
| 21 | + */ | |
| 22 | + | |
| 23 | +#include <linux/slab.h> | |
| 24 | +#include <linux/dma-mapping.h> | |
| 25 | +#include <linux/export.h> | |
| 26 | +#include <video/mmp_disp.h> | |
| 27 | + | |
| 28 | +static struct mmp_overlay *path_get_overlay(struct mmp_path *path, | |
| 29 | + int overlay_id) | |
| 30 | +{ | |
| 31 | + if (path && overlay_id < path->overlay_num) | |
| 32 | + return &path->overlays[overlay_id]; | |
| 33 | + return 0; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static int path_check_status(struct mmp_path *path) | |
| 37 | +{ | |
| 38 | + int i; | |
| 39 | + for (i = 0; i < path->overlay_num; i++) | |
| 40 | + if (path->overlays[i].status) | |
| 41 | + return 1; | |
| 42 | + | |
| 43 | + return 0; | |
| 44 | +} | |
| 45 | + | |
| 46 | +/* | |
| 47 | + * Get modelist write pointer of modelist. | |
| 48 | + * It also returns modelist number | |
| 49 | + * this function fetches modelist from phy/panel: | |
| 50 | + * for HDMI/parallel or dsi to hdmi cases, get from phy | |
| 51 | + * or get from panel | |
| 52 | + */ | |
| 53 | +static int path_get_modelist(struct mmp_path *path, | |
| 54 | + struct mmp_mode **modelist) | |
| 55 | +{ | |
| 56 | + BUG_ON(!path || !modelist); | |
| 57 | + | |
| 58 | + if (path->panel && path->panel->get_modelist) | |
| 59 | + return path->panel->get_modelist(path->panel, modelist); | |
| 60 | + | |
| 61 | + return 0; | |
| 62 | +} | |
| 63 | + | |
| 64 | +/* | |
| 65 | + * panel list is used to pair panel/path when path/panel registered | |
| 66 | + * path list is used for both buffer driver and platdriver | |
| 67 | + * plat driver do path register/unregister | |
| 68 | + * panel driver do panel register/unregister | |
| 69 | + * buffer driver get registered path | |
| 70 | + */ | |
| 71 | +static LIST_HEAD(panel_list); | |
| 72 | +static LIST_HEAD(path_list); | |
| 73 | +static DEFINE_MUTEX(disp_lock); | |
| 74 | + | |
| 75 | +/* | |
| 76 | + * mmp_register_panel - register panel to panel_list and connect to path | |
| 77 | + * @p: panel to be registered | |
| 78 | + * | |
| 79 | + * this function provides interface for panel drivers to register panel | |
| 80 | + * to panel_list and connect to path which matchs panel->plat_path_name. | |
| 81 | + * no error returns when no matching path is found as path register after | |
| 82 | + * panel register is permitted. | |
| 83 | + */ | |
| 84 | +void mmp_register_panel(struct mmp_panel *panel) | |
| 85 | +{ | |
| 86 | + struct mmp_path *path; | |
| 87 | + | |
| 88 | + mutex_lock(&disp_lock); | |
| 89 | + | |
| 90 | + /* add */ | |
| 91 | + list_add_tail(&panel->node, &panel_list); | |
| 92 | + | |
| 93 | + /* try to register to path */ | |
| 94 | + list_for_each_entry(path, &path_list, node) { | |
| 95 | + if (!strcmp(panel->plat_path_name, path->name)) { | |
| 96 | + dev_info(panel->dev, "connect to path %s\n", | |
| 97 | + path->name); | |
| 98 | + path->panel = panel; | |
| 99 | + break; | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + mutex_unlock(&disp_lock); | |
| 104 | +} | |
| 105 | +EXPORT_SYMBOL_GPL(mmp_register_panel); | |
| 106 | + | |
| 107 | +/* | |
| 108 | + * mmp_unregister_panel - unregister panel from panel_list and disconnect | |
| 109 | + * @p: panel to be unregistered | |
| 110 | + * | |
| 111 | + * this function provides interface for panel drivers to unregister panel | |
| 112 | + * from panel_list and disconnect from path. | |
| 113 | + */ | |
| 114 | +void mmp_unregister_panel(struct mmp_panel *panel) | |
| 115 | +{ | |
| 116 | + struct mmp_path *path; | |
| 117 | + | |
| 118 | + mutex_lock(&disp_lock); | |
| 119 | + list_del(&panel->node); | |
| 120 | + | |
| 121 | + list_for_each_entry(path, &path_list, node) { | |
| 122 | + if (path->panel && path->panel == panel) { | |
| 123 | + dev_info(panel->dev, "disconnect from path %s\n", | |
| 124 | + path->name); | |
| 125 | + path->panel = NULL; | |
| 126 | + break; | |
| 127 | + } | |
| 128 | + } | |
| 129 | + mutex_unlock(&disp_lock); | |
| 130 | +} | |
| 131 | +EXPORT_SYMBOL_GPL(mmp_unregister_panel); | |
| 132 | + | |
| 133 | +/* | |
| 134 | + * mmp_get_path - get path by name | |
| 135 | + * @p: path name | |
| 136 | + * | |
| 137 | + * this function checks path name in path_list and return matching path | |
| 138 | + * return NULL if no matching path | |
| 139 | + */ | |
| 140 | +struct mmp_path *mmp_get_path(const char *name) | |
| 141 | +{ | |
| 142 | + struct mmp_path *path; | |
| 143 | + int found = 0; | |
| 144 | + | |
| 145 | + mutex_lock(&disp_lock); | |
| 146 | + list_for_each_entry(path, &path_list, node) { | |
| 147 | + if (!strcmp(name, path->name)) { | |
| 148 | + found = 1; | |
| 149 | + break; | |
| 150 | + } | |
| 151 | + } | |
| 152 | + mutex_unlock(&disp_lock); | |
| 153 | + | |
| 154 | + return found ? path : NULL; | |
| 155 | +} | |
| 156 | +EXPORT_SYMBOL_GPL(mmp_get_path); | |
| 157 | + | |
| 158 | +/* | |
| 159 | + * mmp_register_path - init and register path by path_info | |
| 160 | + * @p: path info provided by display controller | |
| 161 | + * | |
| 162 | + * this function init by path info and register path to path_list | |
| 163 | + * this function also try to connect path with panel by name | |
| 164 | + */ | |
| 165 | +struct mmp_path *mmp_register_path(struct mmp_path_info *info) | |
| 166 | +{ | |
| 167 | + int i; | |
| 168 | + size_t size; | |
| 169 | + struct mmp_path *path = NULL; | |
| 170 | + struct mmp_panel *panel; | |
| 171 | + | |
| 172 | + size = sizeof(struct mmp_path) | |
| 173 | + + sizeof(struct mmp_overlay) * info->overlay_num; | |
| 174 | + path = kzalloc(size, GFP_KERNEL); | |
| 175 | + if (!path) | |
| 176 | + goto failed; | |
| 177 | + | |
| 178 | + /* path set */ | |
| 179 | + mutex_init(&path->access_ok); | |
| 180 | + path->dev = info->dev; | |
| 181 | + path->id = info->id; | |
| 182 | + path->name = info->name; | |
| 183 | + path->output_type = info->output_type; | |
| 184 | + path->overlay_num = info->overlay_num; | |
| 185 | + path->plat_data = info->plat_data; | |
| 186 | + path->ops.set_mode = info->set_mode; | |
| 187 | + | |
| 188 | + mutex_lock(&disp_lock); | |
| 189 | + /* get panel */ | |
| 190 | + list_for_each_entry(panel, &panel_list, node) { | |
| 191 | + if (!strcmp(info->name, panel->plat_path_name)) { | |
| 192 | + dev_info(path->dev, "get panel %s\n", panel->name); | |
| 193 | + path->panel = panel; | |
| 194 | + break; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + dev_info(path->dev, "register %s, overlay_num %d\n", | |
| 199 | + path->name, path->overlay_num); | |
| 200 | + | |
| 201 | + /* default op set: if already set by driver, never cover it */ | |
| 202 | + if (!path->ops.check_status) | |
| 203 | + path->ops.check_status = path_check_status; | |
| 204 | + if (!path->ops.get_overlay) | |
| 205 | + path->ops.get_overlay = path_get_overlay; | |
| 206 | + if (!path->ops.get_modelist) | |
| 207 | + path->ops.get_modelist = path_get_modelist; | |
| 208 | + | |
| 209 | + /* step3: init overlays */ | |
| 210 | + for (i = 0; i < path->overlay_num; i++) { | |
| 211 | + path->overlays[i].path = path; | |
| 212 | + path->overlays[i].id = i; | |
| 213 | + mutex_init(&path->overlays[i].access_ok); | |
| 214 | + path->overlays[i].ops = info->overlay_ops; | |
| 215 | + } | |
| 216 | + | |
| 217 | + /* add to pathlist */ | |
| 218 | + list_add_tail(&path->node, &path_list); | |
| 219 | + | |
| 220 | + mutex_unlock(&disp_lock); | |
| 221 | + return path; | |
| 222 | + | |
| 223 | +failed: | |
| 224 | + kfree(path); | |
| 225 | + mutex_unlock(&disp_lock); | |
| 226 | + return NULL; | |
| 227 | +} | |
| 228 | +EXPORT_SYMBOL_GPL(mmp_register_path); | |
| 229 | + | |
| 230 | +/* | |
| 231 | + * mmp_unregister_path - unregister and destory path | |
| 232 | + * @p: path to be destoried. | |
| 233 | + * | |
| 234 | + * this function registers path and destorys it. | |
| 235 | + */ | |
| 236 | +void mmp_unregister_path(struct mmp_path *path) | |
| 237 | +{ | |
| 238 | + int i; | |
| 239 | + | |
| 240 | + if (!path) | |
| 241 | + return; | |
| 242 | + | |
| 243 | + mutex_lock(&disp_lock); | |
| 244 | + /* del from pathlist */ | |
| 245 | + list_del(&path->node); | |
| 246 | + | |
| 247 | + /* deinit overlays */ | |
| 248 | + for (i = 0; i < path->overlay_num; i++) | |
| 249 | + mutex_destroy(&path->overlays[i].access_ok); | |
| 250 | + | |
| 251 | + mutex_destroy(&path->access_ok); | |
| 252 | + | |
| 253 | + kfree(path); | |
| 254 | + mutex_unlock(&disp_lock); | |
| 255 | + | |
| 256 | + dev_info(path->dev, "de-register %s\n", path->name); | |
| 257 | +} | |
| 258 | +EXPORT_SYMBOL_GPL(mmp_unregister_path); | |
| @@ -0,0 +1,13 @@ | ||
| 1 | +if MMP_DISP | |
| 2 | + | |
| 3 | +config MMP_FB | |
| 4 | + bool "fb driver for Marvell MMP Display Subsystem" | |
| 5 | + depends on FB | |
| 6 | + select FB_CFB_FILLRECT | |
| 7 | + select FB_CFB_COPYAREA | |
| 8 | + select FB_CFB_IMAGEBLIT | |
| 9 | + default y | |
| 10 | + help | |
| 11 | + fb driver for Marvell MMP Display Subsystem | |
| 12 | + | |
| 13 | +endif | |
| @@ -0,0 +1 @@ | ||
| 1 | +obj-$(CONFIG_MMP_FB) += mmpfb.o | |
| @@ -0,0 +1,685 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/fb/mmpfb.c | |
| 3 | + * Framebuffer driver for Marvell Display controller. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Zhou Zhu <zzhu3@marvell.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 14 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 16 | + * more details. | |
| 17 | + * | |
| 18 | + * You should have received a copy of the GNU General Public License along with | |
| 19 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 20 | + * | |
| 21 | + */ | |
| 22 | +#include <linux/module.h> | |
| 23 | +#include <linux/dma-mapping.h> | |
| 24 | +#include <linux/platform_device.h> | |
| 25 | +#include "mmpfb.h" | |
| 26 | + | |
| 27 | +static int var_to_pixfmt(struct fb_var_screeninfo *var) | |
| 28 | +{ | |
| 29 | + /* | |
| 30 | + * Pseudocolor mode? | |
| 31 | + */ | |
| 32 | + if (var->bits_per_pixel == 8) | |
| 33 | + return PIXFMT_PSEUDOCOLOR; | |
| 34 | + | |
| 35 | + /* | |
| 36 | + * Check for YUV422PLANAR. | |
| 37 | + */ | |
| 38 | + if (var->bits_per_pixel == 16 && var->red.length == 8 && | |
| 39 | + var->green.length == 4 && var->blue.length == 4) { | |
| 40 | + if (var->green.offset >= var->blue.offset) | |
| 41 | + return PIXFMT_YUV422P; | |
| 42 | + else | |
| 43 | + return PIXFMT_YVU422P; | |
| 44 | + } | |
| 45 | + | |
| 46 | + /* | |
| 47 | + * Check for YUV420PLANAR. | |
| 48 | + */ | |
| 49 | + if (var->bits_per_pixel == 12 && var->red.length == 8 && | |
| 50 | + var->green.length == 2 && var->blue.length == 2) { | |
| 51 | + if (var->green.offset >= var->blue.offset) | |
| 52 | + return PIXFMT_YUV420P; | |
| 53 | + else | |
| 54 | + return PIXFMT_YVU420P; | |
| 55 | + } | |
| 56 | + | |
| 57 | + /* | |
| 58 | + * Check for YUV422PACK. | |
| 59 | + */ | |
| 60 | + if (var->bits_per_pixel == 16 && var->red.length == 16 && | |
| 61 | + var->green.length == 16 && var->blue.length == 16) { | |
| 62 | + if (var->red.offset == 0) | |
| 63 | + return PIXFMT_YUYV; | |
| 64 | + else if (var->green.offset >= var->blue.offset) | |
| 65 | + return PIXFMT_UYVY; | |
| 66 | + else | |
| 67 | + return PIXFMT_VYUY; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /* | |
| 71 | + * Check for 565/1555. | |
| 72 | + */ | |
| 73 | + if (var->bits_per_pixel == 16 && var->red.length <= 5 && | |
| 74 | + var->green.length <= 6 && var->blue.length <= 5) { | |
| 75 | + if (var->transp.length == 0) { | |
| 76 | + if (var->red.offset >= var->blue.offset) | |
| 77 | + return PIXFMT_RGB565; | |
| 78 | + else | |
| 79 | + return PIXFMT_BGR565; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + | |
| 83 | + /* | |
| 84 | + * Check for 888/A888. | |
| 85 | + */ | |
| 86 | + if (var->bits_per_pixel <= 32 && var->red.length <= 8 && | |
| 87 | + var->green.length <= 8 && var->blue.length <= 8) { | |
| 88 | + if (var->bits_per_pixel == 24 && var->transp.length == 0) { | |
| 89 | + if (var->red.offset >= var->blue.offset) | |
| 90 | + return PIXFMT_RGB888PACK; | |
| 91 | + else | |
| 92 | + return PIXFMT_BGR888PACK; | |
| 93 | + } | |
| 94 | + | |
| 95 | + if (var->bits_per_pixel == 32 && var->transp.offset == 24) { | |
| 96 | + if (var->red.offset >= var->blue.offset) | |
| 97 | + return PIXFMT_RGBA888; | |
| 98 | + else | |
| 99 | + return PIXFMT_BGRA888; | |
| 100 | + } else { | |
| 101 | + if (var->red.offset >= var->blue.offset) | |
| 102 | + return PIXFMT_RGB888UNPACK; | |
| 103 | + else | |
| 104 | + return PIXFMT_BGR888UNPACK; | |
| 105 | + } | |
| 106 | + | |
| 107 | + /* fall through */ | |
| 108 | + } | |
| 109 | + | |
| 110 | + return -EINVAL; | |
| 111 | +} | |
| 112 | + | |
| 113 | +static void pixfmt_to_var(struct fb_var_screeninfo *var, int pix_fmt) | |
| 114 | +{ | |
| 115 | + switch (pix_fmt) { | |
| 116 | + case PIXFMT_RGB565: | |
| 117 | + var->bits_per_pixel = 16; | |
| 118 | + var->red.offset = 11; var->red.length = 5; | |
| 119 | + var->green.offset = 5; var->green.length = 6; | |
| 120 | + var->blue.offset = 0; var->blue.length = 5; | |
| 121 | + var->transp.offset = 0; var->transp.length = 0; | |
| 122 | + break; | |
| 123 | + case PIXFMT_BGR565: | |
| 124 | + var->bits_per_pixel = 16; | |
| 125 | + var->red.offset = 0; var->red.length = 5; | |
| 126 | + var->green.offset = 5; var->green.length = 6; | |
| 127 | + var->blue.offset = 11; var->blue.length = 5; | |
| 128 | + var->transp.offset = 0; var->transp.length = 0; | |
| 129 | + break; | |
| 130 | + case PIXFMT_RGB888UNPACK: | |
| 131 | + var->bits_per_pixel = 32; | |
| 132 | + var->red.offset = 16; var->red.length = 8; | |
| 133 | + var->green.offset = 8; var->green.length = 8; | |
| 134 | + var->blue.offset = 0; var->blue.length = 8; | |
| 135 | + var->transp.offset = 0; var->transp.length = 0; | |
| 136 | + break; | |
| 137 | + case PIXFMT_BGR888UNPACK: | |
| 138 | + var->bits_per_pixel = 32; | |
| 139 | + var->red.offset = 0; var->red.length = 8; | |
| 140 | + var->green.offset = 8; var->green.length = 8; | |
| 141 | + var->blue.offset = 16; var->blue.length = 8; | |
| 142 | + var->transp.offset = 0; var->transp.length = 0; | |
| 143 | + break; | |
| 144 | + case PIXFMT_RGBA888: | |
| 145 | + var->bits_per_pixel = 32; | |
| 146 | + var->red.offset = 16; var->red.length = 8; | |
| 147 | + var->green.offset = 8; var->green.length = 8; | |
| 148 | + var->blue.offset = 0; var->blue.length = 8; | |
| 149 | + var->transp.offset = 24; var->transp.length = 8; | |
| 150 | + break; | |
| 151 | + case PIXFMT_BGRA888: | |
| 152 | + var->bits_per_pixel = 32; | |
| 153 | + var->red.offset = 0; var->red.length = 8; | |
| 154 | + var->green.offset = 8; var->green.length = 8; | |
| 155 | + var->blue.offset = 16; var->blue.length = 8; | |
| 156 | + var->transp.offset = 24; var->transp.length = 8; | |
| 157 | + break; | |
| 158 | + case PIXFMT_RGB888PACK: | |
| 159 | + var->bits_per_pixel = 24; | |
| 160 | + var->red.offset = 16; var->red.length = 8; | |
| 161 | + var->green.offset = 8; var->green.length = 8; | |
| 162 | + var->blue.offset = 0; var->blue.length = 8; | |
| 163 | + var->transp.offset = 0; var->transp.length = 0; | |
| 164 | + break; | |
| 165 | + case PIXFMT_BGR888PACK: | |
| 166 | + var->bits_per_pixel = 24; | |
| 167 | + var->red.offset = 0; var->red.length = 8; | |
| 168 | + var->green.offset = 8; var->green.length = 8; | |
| 169 | + var->blue.offset = 16; var->blue.length = 8; | |
| 170 | + var->transp.offset = 0; var->transp.length = 0; | |
| 171 | + break; | |
| 172 | + case PIXFMT_YUV420P: | |
| 173 | + var->bits_per_pixel = 12; | |
| 174 | + var->red.offset = 4; var->red.length = 8; | |
| 175 | + var->green.offset = 2; var->green.length = 2; | |
| 176 | + var->blue.offset = 0; var->blue.length = 2; | |
| 177 | + var->transp.offset = 0; var->transp.length = 0; | |
| 178 | + break; | |
| 179 | + case PIXFMT_YVU420P: | |
| 180 | + var->bits_per_pixel = 12; | |
| 181 | + var->red.offset = 4; var->red.length = 8; | |
| 182 | + var->green.offset = 0; var->green.length = 2; | |
| 183 | + var->blue.offset = 2; var->blue.length = 2; | |
| 184 | + var->transp.offset = 0; var->transp.length = 0; | |
| 185 | + break; | |
| 186 | + case PIXFMT_YUV422P: | |
| 187 | + var->bits_per_pixel = 16; | |
| 188 | + var->red.offset = 8; var->red.length = 8; | |
| 189 | + var->green.offset = 4; var->green.length = 4; | |
| 190 | + var->blue.offset = 0; var->blue.length = 4; | |
| 191 | + var->transp.offset = 0; var->transp.length = 0; | |
| 192 | + break; | |
| 193 | + case PIXFMT_YVU422P: | |
| 194 | + var->bits_per_pixel = 16; | |
| 195 | + var->red.offset = 8; var->red.length = 8; | |
| 196 | + var->green.offset = 0; var->green.length = 4; | |
| 197 | + var->blue.offset = 4; var->blue.length = 4; | |
| 198 | + var->transp.offset = 0; var->transp.length = 0; | |
| 199 | + break; | |
| 200 | + case PIXFMT_UYVY: | |
| 201 | + var->bits_per_pixel = 16; | |
| 202 | + var->red.offset = 8; var->red.length = 16; | |
| 203 | + var->green.offset = 4; var->green.length = 16; | |
| 204 | + var->blue.offset = 0; var->blue.length = 16; | |
| 205 | + var->transp.offset = 0; var->transp.length = 0; | |
| 206 | + break; | |
| 207 | + case PIXFMT_VYUY: | |
| 208 | + var->bits_per_pixel = 16; | |
| 209 | + var->red.offset = 8; var->red.length = 16; | |
| 210 | + var->green.offset = 0; var->green.length = 16; | |
| 211 | + var->blue.offset = 4; var->blue.length = 16; | |
| 212 | + var->transp.offset = 0; var->transp.length = 0; | |
| 213 | + break; | |
| 214 | + case PIXFMT_YUYV: | |
| 215 | + var->bits_per_pixel = 16; | |
| 216 | + var->red.offset = 0; var->red.length = 16; | |
| 217 | + var->green.offset = 4; var->green.length = 16; | |
| 218 | + var->blue.offset = 8; var->blue.length = 16; | |
| 219 | + var->transp.offset = 0; var->transp.length = 0; | |
| 220 | + break; | |
| 221 | + case PIXFMT_PSEUDOCOLOR: | |
| 222 | + var->bits_per_pixel = 8; | |
| 223 | + var->red.offset = 0; var->red.length = 8; | |
| 224 | + var->green.offset = 0; var->green.length = 8; | |
| 225 | + var->blue.offset = 0; var->blue.length = 8; | |
| 226 | + var->transp.offset = 0; var->transp.length = 0; | |
| 227 | + break; | |
| 228 | + } | |
| 229 | +} | |
| 230 | + | |
| 231 | +/* | |
| 232 | + * fb framework has its limitation: | |
| 233 | + * 1. input color/output color is not seprated | |
| 234 | + * 2. fb_videomode not include output color | |
| 235 | + * so for fb usage, we keep a output format which is not changed | |
| 236 | + * then it's added for mmpmode | |
| 237 | + */ | |
| 238 | +static void fbmode_to_mmpmode(struct mmp_mode *mode, | |
| 239 | + struct fb_videomode *videomode, int output_fmt) | |
| 240 | +{ | |
| 241 | + u64 div_result = 1000000000000ll; | |
| 242 | + mode->name = videomode->name; | |
| 243 | + mode->refresh = videomode->refresh; | |
| 244 | + mode->xres = videomode->xres; | |
| 245 | + mode->yres = videomode->yres; | |
| 246 | + | |
| 247 | + do_div(div_result, videomode->pixclock); | |
| 248 | + mode->pixclock_freq = (u32)div_result; | |
| 249 | + | |
| 250 | + mode->left_margin = videomode->left_margin; | |
| 251 | + mode->right_margin = videomode->right_margin; | |
| 252 | + mode->upper_margin = videomode->upper_margin; | |
| 253 | + mode->lower_margin = videomode->lower_margin; | |
| 254 | + mode->hsync_len = videomode->hsync_len; | |
| 255 | + mode->vsync_len = videomode->vsync_len; | |
| 256 | + mode->hsync_invert = !!(videomode->sync & FB_SYNC_HOR_HIGH_ACT); | |
| 257 | + mode->vsync_invert = !!(videomode->sync & FB_SYNC_VERT_HIGH_ACT); | |
| 258 | + /* no defined flag in fb, use vmode>>3*/ | |
| 259 | + mode->invert_pixclock = !!(videomode->vmode & 8); | |
| 260 | + mode->pix_fmt_out = output_fmt; | |
| 261 | +} | |
| 262 | + | |
| 263 | +static void mmpmode_to_fbmode(struct fb_videomode *videomode, | |
| 264 | + struct mmp_mode *mode) | |
| 265 | +{ | |
| 266 | + u64 div_result = 1000000000000ll; | |
| 267 | + | |
| 268 | + videomode->name = mode->name; | |
| 269 | + videomode->refresh = mode->refresh; | |
| 270 | + videomode->xres = mode->xres; | |
| 271 | + videomode->yres = mode->yres; | |
| 272 | + | |
| 273 | + do_div(div_result, mode->pixclock_freq); | |
| 274 | + videomode->pixclock = (u32)div_result; | |
| 275 | + | |
| 276 | + videomode->left_margin = mode->left_margin; | |
| 277 | + videomode->right_margin = mode->right_margin; | |
| 278 | + videomode->upper_margin = mode->upper_margin; | |
| 279 | + videomode->lower_margin = mode->lower_margin; | |
| 280 | + videomode->hsync_len = mode->hsync_len; | |
| 281 | + videomode->vsync_len = mode->vsync_len; | |
| 282 | + videomode->sync = (mode->hsync_invert ? FB_SYNC_HOR_HIGH_ACT : 0) | |
| 283 | + | (mode->vsync_invert ? FB_SYNC_VERT_HIGH_ACT : 0); | |
| 284 | + videomode->vmode = mode->invert_pixclock ? 8 : 0; | |
| 285 | +} | |
| 286 | + | |
| 287 | +static int mmpfb_check_var(struct fb_var_screeninfo *var, | |
| 288 | + struct fb_info *info) | |
| 289 | +{ | |
| 290 | + struct mmpfb_info *fbi = info->par; | |
| 291 | + | |
| 292 | + if (var->bits_per_pixel == 8) | |
| 293 | + return -EINVAL; | |
| 294 | + /* | |
| 295 | + * Basic geometry sanity checks. | |
| 296 | + */ | |
| 297 | + if (var->xoffset + var->xres > var->xres_virtual) | |
| 298 | + return -EINVAL; | |
| 299 | + if (var->yoffset + var->yres > var->yres_virtual) | |
| 300 | + return -EINVAL; | |
| 301 | + | |
| 302 | + /* | |
| 303 | + * Check size of framebuffer. | |
| 304 | + */ | |
| 305 | + if (var->xres_virtual * var->yres_virtual * | |
| 306 | + (var->bits_per_pixel >> 3) > fbi->fb_size) | |
| 307 | + return -EINVAL; | |
| 308 | + | |
| 309 | + return 0; | |
| 310 | +} | |
| 311 | + | |
| 312 | +static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) | |
| 313 | +{ | |
| 314 | + return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset; | |
| 315 | +} | |
| 316 | + | |
| 317 | +static u32 to_rgb(u16 red, u16 green, u16 blue) | |
| 318 | +{ | |
| 319 | + red >>= 8; | |
| 320 | + green >>= 8; | |
| 321 | + blue >>= 8; | |
| 322 | + | |
| 323 | + return (red << 16) | (green << 8) | blue; | |
| 324 | +} | |
| 325 | + | |
| 326 | +static int mmpfb_setcolreg(unsigned int regno, unsigned int red, | |
| 327 | + unsigned int green, unsigned int blue, | |
| 328 | + unsigned int trans, struct fb_info *info) | |
| 329 | +{ | |
| 330 | + struct mmpfb_info *fbi = info->par; | |
| 331 | + u32 val; | |
| 332 | + | |
| 333 | + if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) { | |
| 334 | + val = chan_to_field(red, &info->var.red); | |
| 335 | + val |= chan_to_field(green, &info->var.green); | |
| 336 | + val |= chan_to_field(blue , &info->var.blue); | |
| 337 | + fbi->pseudo_palette[regno] = val; | |
| 338 | + } | |
| 339 | + | |
| 340 | + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { | |
| 341 | + val = to_rgb(red, green, blue); | |
| 342 | + /* TODO */ | |
| 343 | + } | |
| 344 | + | |
| 345 | + return 0; | |
| 346 | +} | |
| 347 | + | |
| 348 | +static int mmpfb_pan_display(struct fb_var_screeninfo *var, | |
| 349 | + struct fb_info *info) | |
| 350 | +{ | |
| 351 | + struct mmpfb_info *fbi = info->par; | |
| 352 | + struct mmp_addr addr; | |
| 353 | + | |
| 354 | + memset(&addr, 0, sizeof(addr)); | |
| 355 | + addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset) | |
| 356 | + * var->bits_per_pixel / 8 + fbi->fb_start_dma; | |
| 357 | + mmp_overlay_set_addr(fbi->overlay, &addr); | |
| 358 | + | |
| 359 | + return 0; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static int var_update(struct fb_info *info) | |
| 363 | +{ | |
| 364 | + struct mmpfb_info *fbi = info->par; | |
| 365 | + struct fb_var_screeninfo *var = &info->var; | |
| 366 | + struct fb_videomode *m; | |
| 367 | + int pix_fmt; | |
| 368 | + | |
| 369 | + /* set pix_fmt */ | |
| 370 | + pix_fmt = var_to_pixfmt(var); | |
| 371 | + if (pix_fmt < 0) | |
| 372 | + return -EINVAL; | |
| 373 | + pixfmt_to_var(var, pix_fmt); | |
| 374 | + fbi->pix_fmt = pix_fmt; | |
| 375 | + | |
| 376 | + /* set var according to best video mode*/ | |
| 377 | + m = (struct fb_videomode *)fb_match_mode(var, &info->modelist); | |
| 378 | + if (!m) { | |
| 379 | + dev_err(fbi->dev, "set par: no match mode, use best mode\n"); | |
| 380 | + m = (struct fb_videomode *)fb_find_best_mode(var, | |
| 381 | + &info->modelist); | |
| 382 | + fb_videomode_to_var(var, m); | |
| 383 | + } | |
| 384 | + memcpy(&fbi->mode, m, sizeof(struct fb_videomode)); | |
| 385 | + | |
| 386 | + /* fix to 2* yres */ | |
| 387 | + var->yres_virtual = var->yres * 2; | |
| 388 | + info->fix.visual = (pix_fmt == PIXFMT_PSEUDOCOLOR) ? | |
| 389 | + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | |
| 390 | + info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; | |
| 391 | + info->fix.ypanstep = var->yres; | |
| 392 | + return 0; | |
| 393 | +} | |
| 394 | + | |
| 395 | +static int mmpfb_set_par(struct fb_info *info) | |
| 396 | +{ | |
| 397 | + struct mmpfb_info *fbi = info->par; | |
| 398 | + struct fb_var_screeninfo *var = &info->var; | |
| 399 | + struct mmp_addr addr; | |
| 400 | + struct mmp_win win; | |
| 401 | + struct mmp_mode mode; | |
| 402 | + int ret; | |
| 403 | + | |
| 404 | + ret = var_update(info); | |
| 405 | + if (ret != 0) | |
| 406 | + return ret; | |
| 407 | + | |
| 408 | + /* set window/path according to new videomode */ | |
| 409 | + fbmode_to_mmpmode(&mode, &fbi->mode, fbi->output_fmt); | |
| 410 | + mmp_path_set_mode(fbi->path, &mode); | |
| 411 | + | |
| 412 | + memset(&win, 0, sizeof(win)); | |
| 413 | + win.xsrc = win.xdst = fbi->mode.xres; | |
| 414 | + win.ysrc = win.ydst = fbi->mode.yres; | |
| 415 | + win.pix_fmt = fbi->pix_fmt; | |
| 416 | + mmp_overlay_set_win(fbi->overlay, &win); | |
| 417 | + | |
| 418 | + /* set address always */ | |
| 419 | + memset(&addr, 0, sizeof(addr)); | |
| 420 | + addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset) | |
| 421 | + * var->bits_per_pixel / 8 + fbi->fb_start_dma; | |
| 422 | + mmp_overlay_set_addr(fbi->overlay, &addr); | |
| 423 | + | |
| 424 | + return 0; | |
| 425 | +} | |
| 426 | + | |
| 427 | +static void mmpfb_power(struct mmpfb_info *fbi, int power) | |
| 428 | +{ | |
| 429 | + struct mmp_addr addr; | |
| 430 | + struct mmp_win win; | |
| 431 | + struct fb_var_screeninfo *var = &fbi->fb_info->var; | |
| 432 | + | |
| 433 | + /* for power on, always set address/window again */ | |
| 434 | + if (power) { | |
| 435 | + memset(&win, 0, sizeof(win)); | |
| 436 | + win.xsrc = win.xdst = fbi->mode.xres; | |
| 437 | + win.ysrc = win.ydst = fbi->mode.yres; | |
| 438 | + win.pix_fmt = fbi->pix_fmt; | |
| 439 | + mmp_overlay_set_win(fbi->overlay, &win); | |
| 440 | + | |
| 441 | + /* set address always */ | |
| 442 | + memset(&addr, 0, sizeof(addr)); | |
| 443 | + addr.phys[0] = fbi->fb_start_dma + | |
| 444 | + (var->yoffset * var->xres_virtual + var->xoffset) | |
| 445 | + * var->bits_per_pixel / 8; | |
| 446 | + mmp_overlay_set_addr(fbi->overlay, &addr); | |
| 447 | + } | |
| 448 | + mmp_overlay_set_onoff(fbi->overlay, power); | |
| 449 | +} | |
| 450 | + | |
| 451 | +static int mmpfb_blank(int blank, struct fb_info *info) | |
| 452 | +{ | |
| 453 | + struct mmpfb_info *fbi = info->par; | |
| 454 | + | |
| 455 | + mmpfb_power(fbi, (blank == FB_BLANK_UNBLANK)); | |
| 456 | + | |
| 457 | + return 0; | |
| 458 | +} | |
| 459 | + | |
| 460 | +static struct fb_ops mmpfb_ops = { | |
| 461 | + .owner = THIS_MODULE, | |
| 462 | + .fb_blank = mmpfb_blank, | |
| 463 | + .fb_check_var = mmpfb_check_var, | |
| 464 | + .fb_set_par = mmpfb_set_par, | |
| 465 | + .fb_setcolreg = mmpfb_setcolreg, | |
| 466 | + .fb_pan_display = mmpfb_pan_display, | |
| 467 | + .fb_fillrect = cfb_fillrect, | |
| 468 | + .fb_copyarea = cfb_copyarea, | |
| 469 | + .fb_imageblit = cfb_imageblit, | |
| 470 | +}; | |
| 471 | + | |
| 472 | +static int modes_setup(struct mmpfb_info *fbi) | |
| 473 | +{ | |
| 474 | + struct fb_videomode *videomodes; | |
| 475 | + struct mmp_mode *mmp_modes; | |
| 476 | + struct fb_info *info = fbi->fb_info; | |
| 477 | + int videomode_num, i; | |
| 478 | + | |
| 479 | + /* get videomodes from path */ | |
| 480 | + videomode_num = mmp_path_get_modelist(fbi->path, &mmp_modes); | |
| 481 | + if (!videomode_num) { | |
| 482 | + dev_warn(fbi->dev, "can't get videomode num\n"); | |
| 483 | + return 0; | |
| 484 | + } | |
| 485 | + /* put videomode list to info structure */ | |
| 486 | + videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num, | |
| 487 | + GFP_KERNEL); | |
| 488 | + if (!videomodes) { | |
| 489 | + dev_err(fbi->dev, "can't malloc video modes\n"); | |
| 490 | + return -ENOMEM; | |
| 491 | + } | |
| 492 | + for (i = 0; i < videomode_num; i++) | |
| 493 | + mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]); | |
| 494 | + fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist); | |
| 495 | + | |
| 496 | + /* set videomode[0] as default mode */ | |
| 497 | + memcpy(&fbi->mode, &videomodes[0], sizeof(struct fb_videomode)); | |
| 498 | + fbi->output_fmt = mmp_modes[0].pix_fmt_out; | |
| 499 | + fb_videomode_to_var(&info->var, &fbi->mode); | |
| 500 | + mmp_path_set_mode(fbi->path, &mmp_modes[0]); | |
| 501 | + | |
| 502 | + kfree(videomodes); | |
| 503 | + return videomode_num; | |
| 504 | +} | |
| 505 | + | |
| 506 | +static int fb_info_setup(struct fb_info *info, | |
| 507 | + struct mmpfb_info *fbi) | |
| 508 | +{ | |
| 509 | + int ret = 0; | |
| 510 | + /* Initialise static fb parameters.*/ | |
| 511 | + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | | |
| 512 | + FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; | |
| 513 | + info->node = -1; | |
| 514 | + strcpy(info->fix.id, fbi->name); | |
| 515 | + info->fix.type = FB_TYPE_PACKED_PIXELS; | |
| 516 | + info->fix.type_aux = 0; | |
| 517 | + info->fix.xpanstep = 0; | |
| 518 | + info->fix.ypanstep = info->var.yres; | |
| 519 | + info->fix.ywrapstep = 0; | |
| 520 | + info->fix.accel = FB_ACCEL_NONE; | |
| 521 | + info->fix.smem_start = fbi->fb_start_dma; | |
| 522 | + info->fix.smem_len = fbi->fb_size; | |
| 523 | + info->fix.visual = (fbi->pix_fmt == PIXFMT_PSEUDOCOLOR) ? | |
| 524 | + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | |
| 525 | + info->fix.line_length = info->var.xres_virtual * | |
| 526 | + info->var.bits_per_pixel / 8; | |
| 527 | + info->fbops = &mmpfb_ops; | |
| 528 | + info->pseudo_palette = fbi->pseudo_palette; | |
| 529 | + info->screen_base = fbi->fb_start; | |
| 530 | + info->screen_size = fbi->fb_size; | |
| 531 | + | |
| 532 | + /* For FB framework: Allocate color map and Register framebuffer*/ | |
| 533 | + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) | |
| 534 | + ret = -ENOMEM; | |
| 535 | + | |
| 536 | + return ret; | |
| 537 | +} | |
| 538 | + | |
| 539 | +static void fb_info_clear(struct fb_info *info) | |
| 540 | +{ | |
| 541 | + fb_dealloc_cmap(&info->cmap); | |
| 542 | +} | |
| 543 | + | |
| 544 | +static int mmpfb_probe(struct platform_device *pdev) | |
| 545 | +{ | |
| 546 | + struct mmp_buffer_driver_mach_info *mi; | |
| 547 | + struct fb_info *info = 0; | |
| 548 | + struct mmpfb_info *fbi = 0; | |
| 549 | + int ret, modes_num; | |
| 550 | + | |
| 551 | + mi = pdev->dev.platform_data; | |
| 552 | + if (mi == NULL) { | |
| 553 | + dev_err(&pdev->dev, "no platform data defined\n"); | |
| 554 | + return -EINVAL; | |
| 555 | + } | |
| 556 | + | |
| 557 | + /* initialize fb */ | |
| 558 | + info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev); | |
| 559 | + if (info == NULL) | |
| 560 | + return -ENOMEM; | |
| 561 | + fbi = info->par; | |
| 562 | + if (!fbi) { | |
| 563 | + ret = -EINVAL; | |
| 564 | + goto failed; | |
| 565 | + } | |
| 566 | + | |
| 567 | + /* init fb */ | |
| 568 | + fbi->fb_info = info; | |
| 569 | + platform_set_drvdata(pdev, fbi); | |
| 570 | + fbi->dev = &pdev->dev; | |
| 571 | + fbi->name = mi->name; | |
| 572 | + fbi->pix_fmt = mi->default_pixfmt; | |
| 573 | + pixfmt_to_var(&info->var, fbi->pix_fmt); | |
| 574 | + mutex_init(&fbi->access_ok); | |
| 575 | + | |
| 576 | + /* get display path by name */ | |
| 577 | + fbi->path = mmp_get_path(mi->path_name); | |
| 578 | + if (!fbi->path) { | |
| 579 | + dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name); | |
| 580 | + ret = -EINVAL; | |
| 581 | + goto failed_destroy_mutex; | |
| 582 | + } | |
| 583 | + | |
| 584 | + dev_info(fbi->dev, "path %s get\n", fbi->path->name); | |
| 585 | + | |
| 586 | + /* get overlay */ | |
| 587 | + fbi->overlay = mmp_path_get_overlay(fbi->path, mi->overlay_id); | |
| 588 | + if (!fbi->overlay) { | |
| 589 | + ret = -EINVAL; | |
| 590 | + goto failed_destroy_mutex; | |
| 591 | + } | |
| 592 | + /* set fetch used */ | |
| 593 | + mmp_overlay_set_fetch(fbi->overlay, mi->dmafetch_id); | |
| 594 | + | |
| 595 | + modes_num = modes_setup(fbi); | |
| 596 | + if (modes_num < 0) { | |
| 597 | + ret = modes_num; | |
| 598 | + goto failed_destroy_mutex; | |
| 599 | + } | |
| 600 | + | |
| 601 | + /* | |
| 602 | + * if get modes success, means not hotplug panels, use caculated buffer | |
| 603 | + * or use default size | |
| 604 | + */ | |
| 605 | + if (modes_num > 0) { | |
| 606 | + /* fix to 2* yres */ | |
| 607 | + info->var.yres_virtual = info->var.yres * 2; | |
| 608 | + | |
| 609 | + /* Allocate framebuffer memory: size = modes xy *4 */ | |
| 610 | + fbi->fb_size = info->var.xres_virtual * info->var.yres_virtual | |
| 611 | + * info->var.bits_per_pixel / 8; | |
| 612 | + } else { | |
| 613 | + fbi->fb_size = MMPFB_DEFAULT_SIZE; | |
| 614 | + } | |
| 615 | + | |
| 616 | + fbi->fb_start = dma_alloc_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size), | |
| 617 | + &fbi->fb_start_dma, GFP_KERNEL); | |
| 618 | + if (fbi->fb_start == NULL) { | |
| 619 | + dev_err(&pdev->dev, "can't alloc framebuffer\n"); | |
| 620 | + ret = -ENOMEM; | |
| 621 | + goto failed_destroy_mutex; | |
| 622 | + } | |
| 623 | + memset(fbi->fb_start, 0, fbi->fb_size); | |
| 624 | + dev_info(fbi->dev, "fb %dk allocated\n", fbi->fb_size/1024); | |
| 625 | + | |
| 626 | + /* fb power on */ | |
| 627 | + if (modes_num > 0) | |
| 628 | + mmpfb_power(fbi, 1); | |
| 629 | + | |
| 630 | + ret = fb_info_setup(info, fbi); | |
| 631 | + if (ret < 0) | |
| 632 | + goto failed_free_buff; | |
| 633 | + | |
| 634 | + ret = register_framebuffer(info); | |
| 635 | + if (ret < 0) { | |
| 636 | + dev_err(&pdev->dev, "Failed to register fb: %d\n", ret); | |
| 637 | + ret = -ENXIO; | |
| 638 | + goto failed_clear_info; | |
| 639 | + } | |
| 640 | + | |
| 641 | + dev_info(fbi->dev, "loaded to /dev/fb%d <%s>.\n", | |
| 642 | + info->node, info->fix.id); | |
| 643 | + | |
| 644 | +#ifdef CONFIG_LOGO | |
| 645 | + if (fbi->fb_start) { | |
| 646 | + fb_prepare_logo(info, 0); | |
| 647 | + fb_show_logo(info, 0); | |
| 648 | + } | |
| 649 | +#endif | |
| 650 | + | |
| 651 | + return 0; | |
| 652 | + | |
| 653 | +failed_clear_info: | |
| 654 | + fb_info_clear(info); | |
| 655 | +failed_free_buff: | |
| 656 | + dma_free_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size), fbi->fb_start, | |
| 657 | + fbi->fb_start_dma); | |
| 658 | +failed_destroy_mutex: | |
| 659 | + mutex_destroy(&fbi->access_ok); | |
| 660 | +failed: | |
| 661 | + dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n"); | |
| 662 | + platform_set_drvdata(pdev, NULL); | |
| 663 | + | |
| 664 | + framebuffer_release(info); | |
| 665 | + | |
| 666 | + return ret; | |
| 667 | +} | |
| 668 | + | |
| 669 | +static struct platform_driver mmpfb_driver = { | |
| 670 | + .driver = { | |
| 671 | + .name = "mmp-fb", | |
| 672 | + .owner = THIS_MODULE, | |
| 673 | + }, | |
| 674 | + .probe = mmpfb_probe, | |
| 675 | +}; | |
| 676 | + | |
| 677 | +static int mmpfb_init(void) | |
| 678 | +{ | |
| 679 | + return platform_driver_register(&mmpfb_driver); | |
| 680 | +} | |
| 681 | +module_init(mmpfb_init); | |
| 682 | + | |
| 683 | +MODULE_AUTHOR("Zhou Zhu <zhou.zhu@marvell.com>"); | |
| 684 | +MODULE_DESCRIPTION("Framebuffer driver for Marvell displays"); | |
| 685 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/fb/mmpfb.h | |
| 3 | + * Framebuffer driver for Marvell Display controller. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Zhou Zhu <zzhu3@marvell.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 14 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 16 | + * more details. | |
| 17 | + * | |
| 18 | + * You should have received a copy of the GNU General Public License along with | |
| 19 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 20 | + * | |
| 21 | + */ | |
| 22 | + | |
| 23 | +#ifndef _MMP_FB_H_ | |
| 24 | +#define _MMP_FB_H_ | |
| 25 | + | |
| 26 | +#include <video/mmp_disp.h> | |
| 27 | +#include <linux/fb.h> | |
| 28 | + | |
| 29 | +/* LCD controller private state. */ | |
| 30 | +struct mmpfb_info { | |
| 31 | + struct device *dev; | |
| 32 | + int id; | |
| 33 | + const char *name; | |
| 34 | + | |
| 35 | + struct fb_info *fb_info; | |
| 36 | + /* basicaly videomode is for output */ | |
| 37 | + struct fb_videomode mode; | |
| 38 | + int pix_fmt; | |
| 39 | + | |
| 40 | + void *fb_start; | |
| 41 | + int fb_size; | |
| 42 | + dma_addr_t fb_start_dma; | |
| 43 | + | |
| 44 | + struct mmp_overlay *overlay; | |
| 45 | + struct mmp_path *path; | |
| 46 | + | |
| 47 | + struct mutex access_ok; | |
| 48 | + | |
| 49 | + unsigned int pseudo_palette[16]; | |
| 50 | + int output_fmt; | |
| 51 | +}; | |
| 52 | + | |
| 53 | +#define MMPFB_DEFAULT_SIZE (PAGE_ALIGN(1920 * 1080 * 4 * 2)) | |
| 54 | +#endif /* _MMP_FB_H_ */ | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +if MMP_DISP | |
| 2 | + | |
| 3 | +config MMP_DISP_CONTROLLER | |
| 4 | + bool "mmp display controller hw support" | |
| 5 | + depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988 | |
| 6 | + default n | |
| 7 | + help | |
| 8 | + Marvell MMP display hw controller support | |
| 9 | + this controller is used on Marvell PXA910, | |
| 10 | + MMP2, MMP3, PXA988 chips | |
| 11 | + | |
| 12 | +config MMP_DISP_SPI | |
| 13 | + bool "mmp display controller spi port" | |
| 14 | + depends on MMP_DISP_CONTROLLER && SPI_MASTER | |
| 15 | + default y | |
| 16 | + help | |
| 17 | + Marvell MMP display hw controller spi port support | |
| 18 | + will register as a spi master for panel usage | |
| 19 | + | |
| 20 | +endif | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +obj-$(CONFIG_MMP_DISP_CONTROLLER) += mmp_ctrl.o | |
| 2 | +obj-$(CONFIG_MMP_DISP_SPI) += mmp_spi.o | |
| @@ -0,0 +1,591 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/hw/mmp_ctrl.c | |
| 3 | + * Marvell MMP series Display Controller support | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Guoqing Li <ligq@marvell.com> | |
| 7 | + * Lisa Du <cldu@marvell.com> | |
| 8 | + * Zhou Zhu <zzhu3@marvell.com> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify it | |
| 11 | + * under the terms of the GNU General Public License as published by the | |
| 12 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 13 | + * option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 16 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 17 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 18 | + * more details. | |
| 19 | + * | |
| 20 | + * You should have received a copy of the GNU General Public License along with | |
| 21 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | + * | |
| 23 | + */ | |
| 24 | +#include <linux/module.h> | |
| 25 | +#include <linux/moduleparam.h> | |
| 26 | +#include <linux/kernel.h> | |
| 27 | +#include <linux/errno.h> | |
| 28 | +#include <linux/string.h> | |
| 29 | +#include <linux/interrupt.h> | |
| 30 | +#include <linux/slab.h> | |
| 31 | +#include <linux/delay.h> | |
| 32 | +#include <linux/platform_device.h> | |
| 33 | +#include <linux/dma-mapping.h> | |
| 34 | +#include <linux/clk.h> | |
| 35 | +#include <linux/err.h> | |
| 36 | +#include <linux/vmalloc.h> | |
| 37 | +#include <linux/uaccess.h> | |
| 38 | +#include <linux/kthread.h> | |
| 39 | +#include <linux/io.h> | |
| 40 | + | |
| 41 | +#include "mmp_ctrl.h" | |
| 42 | + | |
| 43 | +static irqreturn_t ctrl_handle_irq(int irq, void *dev_id) | |
| 44 | +{ | |
| 45 | + struct mmphw_ctrl *ctrl = (struct mmphw_ctrl *)dev_id; | |
| 46 | + u32 isr, imask, tmp; | |
| 47 | + | |
| 48 | + isr = readl_relaxed(ctrl->reg_base + SPU_IRQ_ISR); | |
| 49 | + imask = readl_relaxed(ctrl->reg_base + SPU_IRQ_ENA); | |
| 50 | + | |
| 51 | + do { | |
| 52 | + /* clear clock only */ | |
| 53 | + tmp = readl_relaxed(ctrl->reg_base + SPU_IRQ_ISR); | |
| 54 | + if (tmp & isr) | |
| 55 | + writel_relaxed(~isr, ctrl->reg_base + SPU_IRQ_ISR); | |
| 56 | + } while ((isr = readl(ctrl->reg_base + SPU_IRQ_ISR)) & imask); | |
| 57 | + | |
| 58 | + return IRQ_HANDLED; | |
| 59 | +} | |
| 60 | + | |
| 61 | +static u32 fmt_to_reg(struct mmp_overlay *overlay, int pix_fmt) | |
| 62 | +{ | |
| 63 | + u32 link_config = path_to_path_plat(overlay->path)->link_config; | |
| 64 | + u32 rbswap, uvswap = 0, yuvswap = 0, | |
| 65 | + csc_en = 0, val = 0, | |
| 66 | + vid = overlay_is_vid(overlay); | |
| 67 | + | |
| 68 | + switch (pix_fmt) { | |
| 69 | + case PIXFMT_RGB565: | |
| 70 | + case PIXFMT_RGB1555: | |
| 71 | + case PIXFMT_RGB888PACK: | |
| 72 | + case PIXFMT_RGB888UNPACK: | |
| 73 | + case PIXFMT_RGBA888: | |
| 74 | + rbswap = !(link_config & 0x1); | |
| 75 | + break; | |
| 76 | + case PIXFMT_VYUY: | |
| 77 | + case PIXFMT_YVU422P: | |
| 78 | + case PIXFMT_YVU420P: | |
| 79 | + rbswap = link_config & 0x1; | |
| 80 | + uvswap = 1; | |
| 81 | + break; | |
| 82 | + case PIXFMT_YUYV: | |
| 83 | + rbswap = link_config & 0x1; | |
| 84 | + yuvswap = 1; | |
| 85 | + break; | |
| 86 | + default: | |
| 87 | + rbswap = link_config & 0x1; | |
| 88 | + break; | |
| 89 | + } | |
| 90 | + | |
| 91 | + switch (pix_fmt) { | |
| 92 | + case PIXFMT_RGB565: | |
| 93 | + case PIXFMT_BGR565: | |
| 94 | + val = 0; | |
| 95 | + break; | |
| 96 | + case PIXFMT_RGB1555: | |
| 97 | + case PIXFMT_BGR1555: | |
| 98 | + val = 0x1; | |
| 99 | + break; | |
| 100 | + case PIXFMT_RGB888PACK: | |
| 101 | + case PIXFMT_BGR888PACK: | |
| 102 | + val = 0x2; | |
| 103 | + break; | |
| 104 | + case PIXFMT_RGB888UNPACK: | |
| 105 | + case PIXFMT_BGR888UNPACK: | |
| 106 | + val = 0x3; | |
| 107 | + break; | |
| 108 | + case PIXFMT_RGBA888: | |
| 109 | + case PIXFMT_BGRA888: | |
| 110 | + val = 0x4; | |
| 111 | + break; | |
| 112 | + case PIXFMT_UYVY: | |
| 113 | + case PIXFMT_VYUY: | |
| 114 | + case PIXFMT_YUYV: | |
| 115 | + val = 0x5; | |
| 116 | + csc_en = 1; | |
| 117 | + break; | |
| 118 | + case PIXFMT_YUV422P: | |
| 119 | + case PIXFMT_YVU422P: | |
| 120 | + val = 0x6; | |
| 121 | + csc_en = 1; | |
| 122 | + break; | |
| 123 | + case PIXFMT_YUV420P: | |
| 124 | + case PIXFMT_YVU420P: | |
| 125 | + val = 0x7; | |
| 126 | + csc_en = 1; | |
| 127 | + break; | |
| 128 | + default: | |
| 129 | + break; | |
| 130 | + } | |
| 131 | + | |
| 132 | + return (dma_palette(0) | dma_fmt(vid, val) | | |
| 133 | + dma_swaprb(vid, rbswap) | dma_swapuv(vid, uvswap) | | |
| 134 | + dma_swapyuv(vid, yuvswap) | dma_csc(vid, csc_en)); | |
| 135 | +} | |
| 136 | + | |
| 137 | +static void dmafetch_set_fmt(struct mmp_overlay *overlay) | |
| 138 | +{ | |
| 139 | + u32 tmp; | |
| 140 | + struct mmp_path *path = overlay->path; | |
| 141 | + tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 142 | + tmp &= ~dma_mask(overlay_is_vid(overlay)); | |
| 143 | + tmp |= fmt_to_reg(overlay, overlay->win.pix_fmt); | |
| 144 | + writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 145 | +} | |
| 146 | + | |
| 147 | +static void overlay_set_win(struct mmp_overlay *overlay, struct mmp_win *win) | |
| 148 | +{ | |
| 149 | + struct lcd_regs *regs = path_regs(overlay->path); | |
| 150 | + u32 pitch; | |
| 151 | + | |
| 152 | + /* assert win supported */ | |
| 153 | + memcpy(&overlay->win, win, sizeof(struct mmp_win)); | |
| 154 | + | |
| 155 | + mutex_lock(&overlay->access_ok); | |
| 156 | + pitch = win->xsrc * pixfmt_to_stride(win->pix_fmt); | |
| 157 | + writel_relaxed(pitch, ®s->g_pitch); | |
| 158 | + writel_relaxed((win->ysrc << 16) | win->xsrc, ®s->g_size); | |
| 159 | + writel_relaxed((win->ydst << 16) | win->xdst, ®s->g_size_z); | |
| 160 | + writel_relaxed(0, ®s->g_start); | |
| 161 | + | |
| 162 | + dmafetch_set_fmt(overlay); | |
| 163 | + mutex_unlock(&overlay->access_ok); | |
| 164 | +} | |
| 165 | + | |
| 166 | +static void dmafetch_onoff(struct mmp_overlay *overlay, int on) | |
| 167 | +{ | |
| 168 | + u32 mask = overlay_is_vid(overlay) ? CFG_GRA_ENA_MASK : | |
| 169 | + CFG_DMA_ENA_MASK; | |
| 170 | + u32 enable = overlay_is_vid(overlay) ? CFG_GRA_ENA(1) : CFG_DMA_ENA(1); | |
| 171 | + u32 tmp; | |
| 172 | + struct mmp_path *path = overlay->path; | |
| 173 | + | |
| 174 | + mutex_lock(&overlay->access_ok); | |
| 175 | + tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 176 | + tmp &= ~mask; | |
| 177 | + tmp |= (on ? enable : 0); | |
| 178 | + writel(tmp, ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 179 | + mutex_unlock(&overlay->access_ok); | |
| 180 | +} | |
| 181 | + | |
| 182 | +static void path_enabledisable(struct mmp_path *path, int on) | |
| 183 | +{ | |
| 184 | + u32 tmp; | |
| 185 | + mutex_lock(&path->access_ok); | |
| 186 | + tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path)); | |
| 187 | + if (on) | |
| 188 | + tmp &= ~SCLK_DISABLE; | |
| 189 | + else | |
| 190 | + tmp |= SCLK_DISABLE; | |
| 191 | + writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path)); | |
| 192 | + mutex_unlock(&path->access_ok); | |
| 193 | +} | |
| 194 | + | |
| 195 | +static void path_onoff(struct mmp_path *path, int on) | |
| 196 | +{ | |
| 197 | + if (path->status == on) { | |
| 198 | + dev_info(path->dev, "path %s is already %s\n", | |
| 199 | + path->name, stat_name(path->status)); | |
| 200 | + return; | |
| 201 | + } | |
| 202 | + | |
| 203 | + if (on) { | |
| 204 | + path_enabledisable(path, 1); | |
| 205 | + | |
| 206 | + if (path->panel && path->panel->set_onoff) | |
| 207 | + path->panel->set_onoff(path->panel, 1); | |
| 208 | + } else { | |
| 209 | + if (path->panel && path->panel->set_onoff) | |
| 210 | + path->panel->set_onoff(path->panel, 0); | |
| 211 | + | |
| 212 | + path_enabledisable(path, 0); | |
| 213 | + } | |
| 214 | + path->status = on; | |
| 215 | +} | |
| 216 | + | |
| 217 | +static void overlay_set_onoff(struct mmp_overlay *overlay, int on) | |
| 218 | +{ | |
| 219 | + if (overlay->status == on) { | |
| 220 | + dev_info(overlay_to_ctrl(overlay)->dev, "overlay %s is already %s\n", | |
| 221 | + overlay->path->name, stat_name(overlay->status)); | |
| 222 | + return; | |
| 223 | + } | |
| 224 | + overlay->status = on; | |
| 225 | + dmafetch_onoff(overlay, on); | |
| 226 | + if (overlay->path->ops.check_status(overlay->path) | |
| 227 | + != overlay->path->status) | |
| 228 | + path_onoff(overlay->path, on); | |
| 229 | +} | |
| 230 | + | |
| 231 | +static void overlay_set_fetch(struct mmp_overlay *overlay, int fetch_id) | |
| 232 | +{ | |
| 233 | + overlay->dmafetch_id = fetch_id; | |
| 234 | +} | |
| 235 | + | |
| 236 | +static int overlay_set_addr(struct mmp_overlay *overlay, struct mmp_addr *addr) | |
| 237 | +{ | |
| 238 | + struct lcd_regs *regs = path_regs(overlay->path); | |
| 239 | + | |
| 240 | + /* FIXME: assert addr supported */ | |
| 241 | + memcpy(&overlay->addr, addr, sizeof(struct mmp_win)); | |
| 242 | + writel(addr->phys[0], ®s->g_0); | |
| 243 | + | |
| 244 | + return overlay->addr.phys[0]; | |
| 245 | +} | |
| 246 | + | |
| 247 | +static void path_set_mode(struct mmp_path *path, struct mmp_mode *mode) | |
| 248 | +{ | |
| 249 | + struct lcd_regs *regs = path_regs(path); | |
| 250 | + u32 total_x, total_y, vsync_ctrl, tmp, sclk_src, sclk_div, | |
| 251 | + link_config = path_to_path_plat(path)->link_config; | |
| 252 | + | |
| 253 | + /* FIXME: assert videomode supported */ | |
| 254 | + memcpy(&path->mode, mode, sizeof(struct mmp_mode)); | |
| 255 | + | |
| 256 | + mutex_lock(&path->access_ok); | |
| 257 | + | |
| 258 | + /* polarity of timing signals */ | |
| 259 | + tmp = readl_relaxed(ctrl_regs(path) + intf_ctrl(path->id)) & 0x1; | |
| 260 | + tmp |= mode->vsync_invert ? 0 : 0x8; | |
| 261 | + tmp |= mode->hsync_invert ? 0 : 0x4; | |
| 262 | + tmp |= link_config & CFG_DUMBMODE_MASK; | |
| 263 | + tmp |= CFG_DUMB_ENA(1); | |
| 264 | + writel_relaxed(tmp, ctrl_regs(path) + intf_ctrl(path->id)); | |
| 265 | + | |
| 266 | + writel_relaxed((mode->yres << 16) | mode->xres, ®s->screen_active); | |
| 267 | + writel_relaxed((mode->left_margin << 16) | mode->right_margin, | |
| 268 | + ®s->screen_h_porch); | |
| 269 | + writel_relaxed((mode->upper_margin << 16) | mode->lower_margin, | |
| 270 | + ®s->screen_v_porch); | |
| 271 | + total_x = mode->xres + mode->left_margin + mode->right_margin + | |
| 272 | + mode->hsync_len; | |
| 273 | + total_y = mode->yres + mode->upper_margin + mode->lower_margin + | |
| 274 | + mode->vsync_len; | |
| 275 | + writel_relaxed((total_y << 16) | total_x, ®s->screen_size); | |
| 276 | + | |
| 277 | + /* vsync ctrl */ | |
| 278 | + if (path->output_type == PATH_OUT_DSI) | |
| 279 | + vsync_ctrl = 0x01330133; | |
| 280 | + else | |
| 281 | + vsync_ctrl = ((mode->xres + mode->right_margin) << 16) | |
| 282 | + | (mode->xres + mode->right_margin); | |
| 283 | + writel_relaxed(vsync_ctrl, ®s->vsync_ctrl); | |
| 284 | + | |
| 285 | + /* set pixclock div */ | |
| 286 | + sclk_src = clk_get_rate(path_to_ctrl(path)->clk); | |
| 287 | + sclk_div = sclk_src / mode->pixclock_freq; | |
| 288 | + if (sclk_div * mode->pixclock_freq < sclk_src) | |
| 289 | + sclk_div++; | |
| 290 | + | |
| 291 | + dev_info(path->dev, "%s sclk_src %d sclk_div 0x%x pclk %d\n", | |
| 292 | + __func__, sclk_src, sclk_div, mode->pixclock_freq); | |
| 293 | + | |
| 294 | + tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path)); | |
| 295 | + tmp &= ~CLK_INT_DIV_MASK; | |
| 296 | + tmp |= sclk_div; | |
| 297 | + writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path)); | |
| 298 | + | |
| 299 | + mutex_unlock(&path->access_ok); | |
| 300 | +} | |
| 301 | + | |
| 302 | +static struct mmp_overlay_ops mmphw_overlay_ops = { | |
| 303 | + .set_fetch = overlay_set_fetch, | |
| 304 | + .set_onoff = overlay_set_onoff, | |
| 305 | + .set_win = overlay_set_win, | |
| 306 | + .set_addr = overlay_set_addr, | |
| 307 | +}; | |
| 308 | + | |
| 309 | +static void ctrl_set_default(struct mmphw_ctrl *ctrl) | |
| 310 | +{ | |
| 311 | + u32 tmp, irq_mask; | |
| 312 | + | |
| 313 | + /* | |
| 314 | + * LCD Global control(LCD_TOP_CTRL) should be configed before | |
| 315 | + * any other LCD registers read/write, or there maybe issues. | |
| 316 | + */ | |
| 317 | + tmp = readl_relaxed(ctrl->reg_base + LCD_TOP_CTRL); | |
| 318 | + tmp |= 0xfff0; | |
| 319 | + writel_relaxed(tmp, ctrl->reg_base + LCD_TOP_CTRL); | |
| 320 | + | |
| 321 | + | |
| 322 | + /* disable all interrupts */ | |
| 323 | + irq_mask = path_imasks(0) | err_imask(0) | | |
| 324 | + path_imasks(1) | err_imask(1); | |
| 325 | + tmp = readl_relaxed(ctrl->reg_base + SPU_IRQ_ENA); | |
| 326 | + tmp &= ~irq_mask; | |
| 327 | + tmp |= irq_mask; | |
| 328 | + writel_relaxed(tmp, ctrl->reg_base + SPU_IRQ_ENA); | |
| 329 | +} | |
| 330 | + | |
| 331 | +static void path_set_default(struct mmp_path *path) | |
| 332 | +{ | |
| 333 | + struct lcd_regs *regs = path_regs(path); | |
| 334 | + u32 dma_ctrl1, mask, tmp, path_config; | |
| 335 | + | |
| 336 | + path_config = path_to_path_plat(path)->path_config; | |
| 337 | + | |
| 338 | + /* Configure IOPAD: should be parallel only */ | |
| 339 | + if (PATH_OUT_PARALLEL == path->output_type) { | |
| 340 | + mask = CFG_IOPADMODE_MASK | CFG_BURST_MASK | CFG_BOUNDARY_MASK; | |
| 341 | + tmp = readl_relaxed(ctrl_regs(path) + SPU_IOPAD_CONTROL); | |
| 342 | + tmp &= ~mask; | |
| 343 | + tmp |= path_config; | |
| 344 | + writel_relaxed(tmp, ctrl_regs(path) + SPU_IOPAD_CONTROL); | |
| 345 | + } | |
| 346 | + | |
| 347 | + /* Select path clock source */ | |
| 348 | + tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path)); | |
| 349 | + tmp &= ~SCLK_SRC_SEL_MASK; | |
| 350 | + tmp |= path_config; | |
| 351 | + writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path)); | |
| 352 | + | |
| 353 | + /* | |
| 354 | + * Configure default bits: vsync triggers DMA, | |
| 355 | + * power save enable, configure alpha registers to | |
| 356 | + * display 100% graphics, and set pixel command. | |
| 357 | + */ | |
| 358 | + dma_ctrl1 = 0x2032ff81; | |
| 359 | + | |
| 360 | + dma_ctrl1 |= CFG_VSYNC_INV_MASK; | |
| 361 | + writel_relaxed(dma_ctrl1, ctrl_regs(path) + dma_ctrl(1, path->id)); | |
| 362 | + | |
| 363 | + /* Configure default register values */ | |
| 364 | + writel_relaxed(0x00000000, ®s->blank_color); | |
| 365 | + writel_relaxed(0x00000000, ®s->g_1); | |
| 366 | + writel_relaxed(0x00000000, ®s->g_start); | |
| 367 | + | |
| 368 | + /* | |
| 369 | + * 1.enable multiple burst request in DMA AXI | |
| 370 | + * bus arbiter for faster read if not tv path; | |
| 371 | + * 2.enable horizontal smooth filter; | |
| 372 | + */ | |
| 373 | + if (PATH_PN == path->id) { | |
| 374 | + mask = CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK | |
| 375 | + | CFG_ARBFAST_ENA(1); | |
| 376 | + tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 377 | + tmp |= mask; | |
| 378 | + writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 379 | + } else if (PATH_TV == path->id) { | |
| 380 | + mask = CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK | |
| 381 | + | CFG_ARBFAST_ENA(1); | |
| 382 | + tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 383 | + tmp &= ~mask; | |
| 384 | + tmp |= CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK; | |
| 385 | + writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id)); | |
| 386 | + } | |
| 387 | +} | |
| 388 | + | |
| 389 | +static int path_init(struct mmphw_path_plat *path_plat, | |
| 390 | + struct mmp_mach_path_config *config) | |
| 391 | +{ | |
| 392 | + struct mmphw_ctrl *ctrl = path_plat->ctrl; | |
| 393 | + struct mmp_path_info *path_info; | |
| 394 | + struct mmp_path *path = NULL; | |
| 395 | + | |
| 396 | + dev_info(ctrl->dev, "%s: %s\n", __func__, config->name); | |
| 397 | + | |
| 398 | + /* init driver data */ | |
| 399 | + path_info = kzalloc(sizeof(struct mmp_path_info), GFP_KERNEL); | |
| 400 | + if (!path_info) { | |
| 401 | + dev_err(ctrl->dev, "%s: unable to alloc path_info for %s\n", | |
| 402 | + __func__, config->name); | |
| 403 | + return 0; | |
| 404 | + } | |
| 405 | + path_info->name = config->name; | |
| 406 | + path_info->id = path_plat->id; | |
| 407 | + path_info->dev = ctrl->dev; | |
| 408 | + path_info->overlay_num = config->overlay_num; | |
| 409 | + path_info->overlay_ops = &mmphw_overlay_ops; | |
| 410 | + path_info->set_mode = path_set_mode; | |
| 411 | + path_info->plat_data = path_plat; | |
| 412 | + | |
| 413 | + /* create/register platform device */ | |
| 414 | + path = mmp_register_path(path_info); | |
| 415 | + if (!path) { | |
| 416 | + kfree(path_info); | |
| 417 | + return 0; | |
| 418 | + } | |
| 419 | + path_plat->path = path; | |
| 420 | + path_plat->path_config = config->path_config; | |
| 421 | + path_plat->link_config = config->link_config; | |
| 422 | + path_set_default(path); | |
| 423 | + | |
| 424 | + kfree(path_info); | |
| 425 | + return 1; | |
| 426 | +} | |
| 427 | + | |
| 428 | +static void path_deinit(struct mmphw_path_plat *path_plat) | |
| 429 | +{ | |
| 430 | + if (!path_plat) | |
| 431 | + return; | |
| 432 | + | |
| 433 | + if (path_plat->path) | |
| 434 | + mmp_unregister_path(path_plat->path); | |
| 435 | +} | |
| 436 | + | |
| 437 | +static int mmphw_probe(struct platform_device *pdev) | |
| 438 | +{ | |
| 439 | + struct mmp_mach_plat_info *mi; | |
| 440 | + struct resource *res; | |
| 441 | + int ret, i, size, irq; | |
| 442 | + struct mmphw_path_plat *path_plat; | |
| 443 | + struct mmphw_ctrl *ctrl = NULL; | |
| 444 | + | |
| 445 | + /* get resources from platform data */ | |
| 446 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 447 | + if (res == NULL) { | |
| 448 | + dev_err(&pdev->dev, "%s: no IO memory defined\n", __func__); | |
| 449 | + ret = -ENOENT; | |
| 450 | + goto failed; | |
| 451 | + } | |
| 452 | + | |
| 453 | + irq = platform_get_irq(pdev, 0); | |
| 454 | + if (irq < 0) { | |
| 455 | + dev_err(&pdev->dev, "%s: no IRQ defined\n", __func__); | |
| 456 | + ret = -ENOENT; | |
| 457 | + goto failed; | |
| 458 | + } | |
| 459 | + | |
| 460 | + /* get configs from platform data */ | |
| 461 | + mi = pdev->dev.platform_data; | |
| 462 | + if (mi == NULL || !mi->path_num || !mi->paths) { | |
| 463 | + dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); | |
| 464 | + ret = -EINVAL; | |
| 465 | + goto failed; | |
| 466 | + } | |
| 467 | + | |
| 468 | + /* allocate */ | |
| 469 | + size = sizeof(struct mmphw_ctrl) + sizeof(struct mmphw_path_plat) * | |
| 470 | + mi->path_num; | |
| 471 | + ctrl = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | |
| 472 | + if (!ctrl) { | |
| 473 | + ret = -ENOMEM; | |
| 474 | + goto failed; | |
| 475 | + } | |
| 476 | + | |
| 477 | + ctrl->name = mi->name; | |
| 478 | + ctrl->path_num = mi->path_num; | |
| 479 | + ctrl->dev = &pdev->dev; | |
| 480 | + ctrl->irq = irq; | |
| 481 | + platform_set_drvdata(pdev, ctrl); | |
| 482 | + mutex_init(&ctrl->access_ok); | |
| 483 | + | |
| 484 | + /* map registers.*/ | |
| 485 | + if (!devm_request_mem_region(ctrl->dev, res->start, | |
| 486 | + resource_size(res), ctrl->name)) { | |
| 487 | + dev_err(ctrl->dev, | |
| 488 | + "can't request region for resource %pR\n", res); | |
| 489 | + ret = -EINVAL; | |
| 490 | + goto failed; | |
| 491 | + } | |
| 492 | + | |
| 493 | + ctrl->reg_base = devm_ioremap_nocache(ctrl->dev, | |
| 494 | + res->start, resource_size(res)); | |
| 495 | + if (ctrl->reg_base == NULL) { | |
| 496 | + dev_err(ctrl->dev, "%s: res %x - %x map failed\n", __func__, | |
| 497 | + res->start, res->end); | |
| 498 | + ret = -ENOMEM; | |
| 499 | + goto failed; | |
| 500 | + } | |
| 501 | + | |
| 502 | + /* request irq */ | |
| 503 | + ret = devm_request_irq(ctrl->dev, ctrl->irq, ctrl_handle_irq, | |
| 504 | + IRQF_SHARED, "lcd_controller", ctrl); | |
| 505 | + if (ret < 0) { | |
| 506 | + dev_err(ctrl->dev, "%s unable to request IRQ %d\n", | |
| 507 | + __func__, ctrl->irq); | |
| 508 | + ret = -ENXIO; | |
| 509 | + goto failed; | |
| 510 | + } | |
| 511 | + | |
| 512 | + /* get clock */ | |
| 513 | + ctrl->clk = devm_clk_get(ctrl->dev, mi->clk_name); | |
| 514 | + if (IS_ERR(ctrl->clk)) { | |
| 515 | + dev_err(ctrl->dev, "unable to get clk %s\n", mi->clk_name); | |
| 516 | + ret = -ENOENT; | |
| 517 | + goto failed_get_clk; | |
| 518 | + } | |
| 519 | + clk_prepare_enable(ctrl->clk); | |
| 520 | + | |
| 521 | + /* init global regs */ | |
| 522 | + ctrl_set_default(ctrl); | |
| 523 | + | |
| 524 | + /* init pathes from machine info and register them */ | |
| 525 | + for (i = 0; i < ctrl->path_num; i++) { | |
| 526 | + /* get from config and machine info */ | |
| 527 | + path_plat = &ctrl->path_plats[i]; | |
| 528 | + path_plat->id = i; | |
| 529 | + path_plat->ctrl = ctrl; | |
| 530 | + | |
| 531 | + /* path init */ | |
| 532 | + if (!path_init(path_plat, &mi->paths[i])) { | |
| 533 | + ret = -EINVAL; | |
| 534 | + goto failed_path_init; | |
| 535 | + } | |
| 536 | + } | |
| 537 | + | |
| 538 | +#ifdef CONFIG_MMP_DISP_SPI | |
| 539 | + ret = lcd_spi_register(ctrl); | |
| 540 | + if (ret < 0) | |
| 541 | + goto failed_path_init; | |
| 542 | +#endif | |
| 543 | + | |
| 544 | + dev_info(ctrl->dev, "device init done\n"); | |
| 545 | + | |
| 546 | + return 0; | |
| 547 | + | |
| 548 | +failed_path_init: | |
| 549 | + for (i = 0; i < ctrl->path_num; i++) { | |
| 550 | + path_plat = &ctrl->path_plats[i]; | |
| 551 | + path_deinit(path_plat); | |
| 552 | + } | |
| 553 | + | |
| 554 | + if (ctrl->clk) { | |
| 555 | + devm_clk_put(ctrl->dev, ctrl->clk); | |
| 556 | + clk_disable_unprepare(ctrl->clk); | |
| 557 | + } | |
| 558 | +failed_get_clk: | |
| 559 | + devm_free_irq(ctrl->dev, ctrl->irq, ctrl); | |
| 560 | +failed: | |
| 561 | + if (ctrl) { | |
| 562 | + if (ctrl->reg_base) | |
| 563 | + devm_iounmap(ctrl->dev, ctrl->reg_base); | |
| 564 | + devm_release_mem_region(ctrl->dev, res->start, | |
| 565 | + resource_size(res)); | |
| 566 | + devm_kfree(ctrl->dev, ctrl); | |
| 567 | + } | |
| 568 | + | |
| 569 | + platform_set_drvdata(pdev, NULL); | |
| 570 | + dev_err(&pdev->dev, "device init failed\n"); | |
| 571 | + | |
| 572 | + return ret; | |
| 573 | +} | |
| 574 | + | |
| 575 | +static struct platform_driver mmphw_driver = { | |
| 576 | + .driver = { | |
| 577 | + .name = "mmp-disp", | |
| 578 | + .owner = THIS_MODULE, | |
| 579 | + }, | |
| 580 | + .probe = mmphw_probe, | |
| 581 | +}; | |
| 582 | + | |
| 583 | +static int mmphw_init(void) | |
| 584 | +{ | |
| 585 | + return platform_driver_register(&mmphw_driver); | |
| 586 | +} | |
| 587 | +module_init(mmphw_init); | |
| 588 | + | |
| 589 | +MODULE_AUTHOR("Li Guoqing<ligq@marvell.com>"); | |
| 590 | +MODULE_DESCRIPTION("Framebuffer driver for mmp"); | |
| 591 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,1974 @@ | ||
| 1 | +/* | |
| 2 | + * drivers/video/mmp/hw/mmp_ctrl.h | |
| 3 | + * | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Guoqing Li <ligq@marvell.com> | |
| 7 | + * Lisa Du <cldu@marvell.com> | |
| 8 | + * Zhou Zhu <zzhu3@marvell.com> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify it | |
| 11 | + * under the terms of the GNU General Public License as published by the | |
| 12 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 13 | + * option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 16 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 17 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 18 | + * more details. | |
| 19 | + * | |
| 20 | + * You should have received a copy of the GNU General Public License along with | |
| 21 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | + * | |
| 23 | + */ | |
| 24 | + | |
| 25 | +#ifndef _MMP_CTRL_H_ | |
| 26 | +#define _MMP_CTRL_H_ | |
| 27 | + | |
| 28 | +#include <video/mmp_disp.h> | |
| 29 | + | |
| 30 | +/* ------------< LCD register >------------ */ | |
| 31 | +struct lcd_regs { | |
| 32 | +/* TV patch register for MMP2 */ | |
| 33 | +/* 32 bit TV Video Frame0 Y Starting Address */ | |
| 34 | +#define LCD_TVD_START_ADDR_Y0 (0x0000) | |
| 35 | +/* 32 bit TV Video Frame0 U Starting Address */ | |
| 36 | +#define LCD_TVD_START_ADDR_U0 (0x0004) | |
| 37 | +/* 32 bit TV Video Frame0 V Starting Address */ | |
| 38 | +#define LCD_TVD_START_ADDR_V0 (0x0008) | |
| 39 | +/* 32 bit TV Video Frame0 Command Starting Address */ | |
| 40 | +#define LCD_TVD_START_ADDR_C0 (0x000C) | |
| 41 | +/* 32 bit TV Video Frame1 Y Starting Address Register*/ | |
| 42 | +#define LCD_TVD_START_ADDR_Y1 (0x0010) | |
| 43 | +/* 32 bit TV Video Frame1 U Starting Address Register*/ | |
| 44 | +#define LCD_TVD_START_ADDR_U1 (0x0014) | |
| 45 | +/* 32 bit TV Video Frame1 V Starting Address Register*/ | |
| 46 | +#define LCD_TVD_START_ADDR_V1 (0x0018) | |
| 47 | +/* 32 bit TV Video Frame1 Command Starting Address Register*/ | |
| 48 | +#define LCD_TVD_START_ADDR_C1 (0x001C) | |
| 49 | +/* 32 bit TV Video Y andC Line Length(Pitch)Register*/ | |
| 50 | +#define LCD_TVD_PITCH_YC (0x0020) | |
| 51 | +/* 32 bit TV Video U andV Line Length(Pitch)Register*/ | |
| 52 | +#define LCD_TVD_PITCH_UV (0x0024) | |
| 53 | +/* 32 bit TV Video Starting Point on Screen Register*/ | |
| 54 | +#define LCD_TVD_OVSA_HPXL_VLN (0x0028) | |
| 55 | +/* 32 bit TV Video Source Size Register*/ | |
| 56 | +#define LCD_TVD_HPXL_VLN (0x002C) | |
| 57 | +/* 32 bit TV Video Destination Size (After Zooming)Register*/ | |
| 58 | +#define LCD_TVDZM_HPXL_VLN (0x0030) | |
| 59 | + u32 v_y0; | |
| 60 | + u32 v_u0; | |
| 61 | + u32 v_v0; | |
| 62 | + u32 v_c0; | |
| 63 | + u32 v_y1; | |
| 64 | + u32 v_u1; | |
| 65 | + u32 v_v1; | |
| 66 | + u32 v_c1; | |
| 67 | + u32 v_pitch_yc; /* Video Y and C Line Length (Pitch) */ | |
| 68 | + u32 v_pitch_uv; /* Video U and V Line Length (Pitch) */ | |
| 69 | + u32 v_start; /* Video Starting Point on Screen */ | |
| 70 | + u32 v_size; /* Video Source Size */ | |
| 71 | + u32 v_size_z; /* Video Destination Size (After Zooming) */ | |
| 72 | + | |
| 73 | +/* 32 bit TV Graphic Frame 0 Starting Address Register*/ | |
| 74 | +#define LCD_TVG_START_ADDR0 (0x0034) | |
| 75 | +/* 32 bit TV Graphic Frame 1 Starting Address Register*/ | |
| 76 | +#define LCD_TVG_START_ADDR1 (0x0038) | |
| 77 | +/* 32 bit TV Graphic Line Length(Pitch)Register*/ | |
| 78 | +#define LCD_TVG_PITCH (0x003C) | |
| 79 | +/* 32 bit TV Graphic Starting Point on Screen Register*/ | |
| 80 | +#define LCD_TVG_OVSA_HPXL_VLN (0x0040) | |
| 81 | +/* 32 bit TV Graphic Source Size Register*/ | |
| 82 | +#define LCD_TVG_HPXL_VLN (0x0044) | |
| 83 | +/* 32 bit TV Graphic Destination size (after Zooming)Register*/ | |
| 84 | +#define LCD_TVGZM_HPXL_VLN (0x0048) | |
| 85 | + u32 g_0; /* Graphic Frame 0/1 Starting Address */ | |
| 86 | + u32 g_1; | |
| 87 | + u32 g_pitch; /* Graphic Line Length (Pitch) */ | |
| 88 | + u32 g_start; /* Graphic Starting Point on Screen */ | |
| 89 | + u32 g_size; /* Graphic Source Size */ | |
| 90 | + u32 g_size_z; /* Graphic Destination Size (After Zooming) */ | |
| 91 | + | |
| 92 | +/* 32 bit TV Hardware Cursor Starting Point on screen Register*/ | |
| 93 | +#define LCD_TVC_OVSA_HPXL_VLN (0x004C) | |
| 94 | +/* 32 bit TV Hardware Cursor Size Register */ | |
| 95 | +#define LCD_TVC_HPXL_VLN (0x0050) | |
| 96 | + u32 hc_start; /* Hardware Cursor */ | |
| 97 | + u32 hc_size; /* Hardware Cursor */ | |
| 98 | + | |
| 99 | +/* 32 bit TV Total Screen Size Register*/ | |
| 100 | +#define LCD_TV_V_H_TOTAL (0x0054) | |
| 101 | +/* 32 bit TV Screen Active Size Register*/ | |
| 102 | +#define LCD_TV_V_H_ACTIVE (0x0058) | |
| 103 | +/* 32 bit TV Screen Horizontal Porch Register*/ | |
| 104 | +#define LCD_TV_H_PORCH (0x005C) | |
| 105 | +/* 32 bit TV Screen Vertical Porch Register*/ | |
| 106 | +#define LCD_TV_V_PORCH (0x0060) | |
| 107 | + u32 screen_size; /* Screen Total Size */ | |
| 108 | + u32 screen_active; /* Screen Active Size */ | |
| 109 | + u32 screen_h_porch; /* Screen Horizontal Porch */ | |
| 110 | + u32 screen_v_porch; /* Screen Vertical Porch */ | |
| 111 | + | |
| 112 | +/* 32 bit TV Screen Blank Color Register*/ | |
| 113 | +#define LCD_TV_BLANKCOLOR (0x0064) | |
| 114 | +/* 32 bit TV Hardware Cursor Color1 Register*/ | |
| 115 | +#define LCD_TV_ALPHA_COLOR1 (0x0068) | |
| 116 | +/* 32 bit TV Hardware Cursor Color2 Register*/ | |
| 117 | +#define LCD_TV_ALPHA_COLOR2 (0x006C) | |
| 118 | + u32 blank_color; /* Screen Blank Color */ | |
| 119 | + u32 hc_Alpha_color1; /* Hardware Cursor Color1 */ | |
| 120 | + u32 hc_Alpha_color2; /* Hardware Cursor Color2 */ | |
| 121 | + | |
| 122 | +/* 32 bit TV Video Y Color Key Control*/ | |
| 123 | +#define LCD_TV_COLORKEY_Y (0x0070) | |
| 124 | +/* 32 bit TV Video U Color Key Control*/ | |
| 125 | +#define LCD_TV_COLORKEY_U (0x0074) | |
| 126 | +/* 32 bit TV Video V Color Key Control*/ | |
| 127 | +#define LCD_TV_COLORKEY_V (0x0078) | |
| 128 | + u32 v_colorkey_y; /* Video Y Color Key Control */ | |
| 129 | + u32 v_colorkey_u; /* Video U Color Key Control */ | |
| 130 | + u32 v_colorkey_v; /* Video V Color Key Control */ | |
| 131 | + | |
| 132 | +/* 32 bit TV VSYNC PulsePixel Edge Control Register*/ | |
| 133 | +#define LCD_TV_SEPXLCNT (0x007C) | |
| 134 | + u32 vsync_ctrl; /* VSYNC PulsePixel Edge Control */ | |
| 135 | +}; | |
| 136 | + | |
| 137 | +#define intf_ctrl(id) ((id) ? (((id) & 1) ? LCD_TVIF_CTRL : \ | |
| 138 | + LCD_DUMB2_CTRL) : LCD_SPU_DUMB_CTRL) | |
| 139 | +#define dma_ctrl0(id) ((id) ? (((id) & 1) ? LCD_TV_CTRL0 : \ | |
| 140 | + LCD_PN2_CTRL0) : LCD_SPU_DMA_CTRL0) | |
| 141 | +#define dma_ctrl1(id) ((id) ? (((id) & 1) ? LCD_TV_CTRL1 : \ | |
| 142 | + LCD_PN2_CTRL1) : LCD_SPU_DMA_CTRL1) | |
| 143 | +#define dma_ctrl(ctrl1, id) (ctrl1 ? dma_ctrl1(id) : dma_ctrl0(id)) | |
| 144 | + | |
| 145 | +/* 32 bit TV Path DMA Control 0*/ | |
| 146 | +#define LCD_TV_CTRL0 (0x0080) | |
| 147 | +/* 32 bit TV Path DMA Control 1*/ | |
| 148 | +#define LCD_TV_CTRL1 (0x0084) | |
| 149 | +/* 32 bit TV Path Video Contrast*/ | |
| 150 | +#define LCD_TV_CONTRAST (0x0088) | |
| 151 | +/* 32 bit TV Path Video Saturation*/ | |
| 152 | +#define LCD_TV_SATURATION (0x008C) | |
| 153 | +/* 32 bit TV Path Video Hue Adjust*/ | |
| 154 | +#define LCD_TV_CBSH_HUE (0x0090) | |
| 155 | +/* 32 bit TV Path TVIF Control Register */ | |
| 156 | +#define LCD_TVIF_CTRL (0x0094) | |
| 157 | +#define TV_VBLNK_VALID_EN (1 << 12) | |
| 158 | + | |
| 159 | +/* 32 bit TV Path I/O Pad Control*/ | |
| 160 | +#define LCD_TVIOPAD_CTRL (0x0098) | |
| 161 | +/* 32 bit TV Path Cloc Divider */ | |
| 162 | +#define LCD_TCLK_DIV (0x009C) | |
| 163 | + | |
| 164 | +#define LCD_SCLK(path) ((PATH_PN == path->id) ? LCD_CFG_SCLK_DIV :\ | |
| 165 | + ((PATH_TV == path->id) ? LCD_TCLK_DIV : LCD_PN2_SCLK_DIV)) | |
| 166 | + | |
| 167 | +/* dither configure */ | |
| 168 | +#ifdef CONFIG_CPU_PXA988 | |
| 169 | +#define LCD_DITHER_CTRL (0x01EC) | |
| 170 | +#else | |
| 171 | +#define LCD_DITHER_CTRL (0x00A0) | |
| 172 | +#endif | |
| 173 | + | |
| 174 | +#define DITHER_TBL_INDEX_SEL(s) ((s) << 16) | |
| 175 | +#define DITHER_MODE2(m) ((m) << 12) | |
| 176 | +#define DITHER_MODE2_SHIFT (12) | |
| 177 | +#define DITHER_4X8_EN2 (1 << 9) | |
| 178 | +#define DITHER_4X8_EN2_SHIFT (9) | |
| 179 | +#define DITHER_EN2 (1 << 8) | |
| 180 | +#define DITHER_MODE1(m) ((m) << 4) | |
| 181 | +#define DITHER_MODE1_SHIFT (4) | |
| 182 | +#define DITHER_4X8_EN1 (1 << 1) | |
| 183 | +#define DITHER_4X8_EN1_SHIFT (1) | |
| 184 | +#define DITHER_EN1 (1) | |
| 185 | + | |
| 186 | +/* dither table data was fixed by video bpp of input and output*/ | |
| 187 | +#ifdef CONFIG_CPU_PXA988 | |
| 188 | +#define DITHER_TB_4X4_INDEX0 (0x6e4ca280) | |
| 189 | +#define DITHER_TB_4X4_INDEX1 (0x5d7f91b3) | |
| 190 | +#define DITHER_TB_4X8_INDEX0 (0xb391a280) | |
| 191 | +#define DITHER_TB_4X8_INDEX1 (0x7f5d6e4c) | |
| 192 | +#define DITHER_TB_4X8_INDEX2 (0x80a291b3) | |
| 193 | +#define DITHER_TB_4X8_INDEX3 (0x4c6e5d7f) | |
| 194 | +#define LCD_DITHER_TBL_DATA (0x01F0) | |
| 195 | +#else | |
| 196 | +#define DITHER_TB_4X4_INDEX0 (0x3b19f7d5) | |
| 197 | +#define DITHER_TB_4X4_INDEX1 (0x082ac4e6) | |
| 198 | +#define DITHER_TB_4X8_INDEX0 (0xf7d508e6) | |
| 199 | +#define DITHER_TB_4X8_INDEX1 (0x3b194c2a) | |
| 200 | +#define DITHER_TB_4X8_INDEX2 (0xc4e6d5f7) | |
| 201 | +#define DITHER_TB_4X8_INDEX3 (0x082a193b) | |
| 202 | +#define LCD_DITHER_TBL_DATA (0x00A4) | |
| 203 | +#endif | |
| 204 | + | |
| 205 | +/* Video Frame 0&1 start address registers */ | |
| 206 | +#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 | |
| 207 | +#define LCD_SPU_DMA_START_ADDR_U0 0x00C4 | |
| 208 | +#define LCD_SPU_DMA_START_ADDR_V0 0x00C8 | |
| 209 | +#define LCD_CFG_DMA_START_ADDR_0 0x00CC /* Cmd address */ | |
| 210 | +#define LCD_SPU_DMA_START_ADDR_Y1 0x00D0 | |
| 211 | +#define LCD_SPU_DMA_START_ADDR_U1 0x00D4 | |
| 212 | +#define LCD_SPU_DMA_START_ADDR_V1 0x00D8 | |
| 213 | +#define LCD_CFG_DMA_START_ADDR_1 0x00DC /* Cmd address */ | |
| 214 | + | |
| 215 | +/* YC & UV Pitch */ | |
| 216 | +#define LCD_SPU_DMA_PITCH_YC 0x00E0 | |
| 217 | +#define SPU_DMA_PITCH_C(c) ((c)<<16) | |
| 218 | +#define SPU_DMA_PITCH_Y(y) (y) | |
| 219 | +#define LCD_SPU_DMA_PITCH_UV 0x00E4 | |
| 220 | +#define SPU_DMA_PITCH_V(v) ((v)<<16) | |
| 221 | +#define SPU_DMA_PITCH_U(u) (u) | |
| 222 | + | |
| 223 | +/* Video Starting Point on Screen Register */ | |
| 224 | +#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00E8 | |
| 225 | +#define CFG_DMA_OVSA_VLN(y) ((y)<<16) /* 0~0xfff */ | |
| 226 | +#define CFG_DMA_OVSA_HPXL(x) (x) /* 0~0xfff */ | |
| 227 | + | |
| 228 | +/* Video Size Register */ | |
| 229 | +#define LCD_SPU_DMA_HPXL_VLN 0x00EC | |
| 230 | +#define CFG_DMA_VLN(y) ((y)<<16) | |
| 231 | +#define CFG_DMA_HPXL(x) (x) | |
| 232 | + | |
| 233 | +/* Video Size After zooming Register */ | |
| 234 | +#define LCD_SPU_DZM_HPXL_VLN 0x00F0 | |
| 235 | +#define CFG_DZM_VLN(y) ((y)<<16) | |
| 236 | +#define CFG_DZM_HPXL(x) (x) | |
| 237 | + | |
| 238 | +/* Graphic Frame 0&1 Starting Address Register */ | |
| 239 | +#define LCD_CFG_GRA_START_ADDR0 0x00F4 | |
| 240 | +#define LCD_CFG_GRA_START_ADDR1 0x00F8 | |
| 241 | + | |
| 242 | +/* Graphic Frame Pitch */ | |
| 243 | +#define LCD_CFG_GRA_PITCH 0x00FC | |
| 244 | + | |
| 245 | +/* Graphic Starting Point on Screen Register */ | |
| 246 | +#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100 | |
| 247 | +#define CFG_GRA_OVSA_VLN(y) ((y)<<16) | |
| 248 | +#define CFG_GRA_OVSA_HPXL(x) (x) | |
| 249 | + | |
| 250 | +/* Graphic Size Register */ | |
| 251 | +#define LCD_SPU_GRA_HPXL_VLN 0x0104 | |
| 252 | +#define CFG_GRA_VLN(y) ((y)<<16) | |
| 253 | +#define CFG_GRA_HPXL(x) (x) | |
| 254 | + | |
| 255 | +/* Graphic Size after Zooming Register */ | |
| 256 | +#define LCD_SPU_GZM_HPXL_VLN 0x0108 | |
| 257 | +#define CFG_GZM_VLN(y) ((y)<<16) | |
| 258 | +#define CFG_GZM_HPXL(x) (x) | |
| 259 | + | |
| 260 | +/* HW Cursor Starting Point on Screen Register */ | |
| 261 | +#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010C | |
| 262 | +#define CFG_HWC_OVSA_VLN(y) ((y)<<16) | |
| 263 | +#define CFG_HWC_OVSA_HPXL(x) (x) | |
| 264 | + | |
| 265 | +/* HW Cursor Size */ | |
| 266 | +#define LCD_SPU_HWC_HPXL_VLN 0x0110 | |
| 267 | +#define CFG_HWC_VLN(y) ((y)<<16) | |
| 268 | +#define CFG_HWC_HPXL(x) (x) | |
| 269 | + | |
| 270 | +/* Total Screen Size Register */ | |
| 271 | +#define LCD_SPUT_V_H_TOTAL 0x0114 | |
| 272 | +#define CFG_V_TOTAL(y) ((y)<<16) | |
| 273 | +#define CFG_H_TOTAL(x) (x) | |
| 274 | + | |
| 275 | +/* Total Screen Active Size Register */ | |
| 276 | +#define LCD_SPU_V_H_ACTIVE 0x0118 | |
| 277 | +#define CFG_V_ACTIVE(y) ((y)<<16) | |
| 278 | +#define CFG_H_ACTIVE(x) (x) | |
| 279 | + | |
| 280 | +/* Screen H&V Porch Register */ | |
| 281 | +#define LCD_SPU_H_PORCH 0x011C | |
| 282 | +#define CFG_H_BACK_PORCH(b) ((b)<<16) | |
| 283 | +#define CFG_H_FRONT_PORCH(f) (f) | |
| 284 | +#define LCD_SPU_V_PORCH 0x0120 | |
| 285 | +#define CFG_V_BACK_PORCH(b) ((b)<<16) | |
| 286 | +#define CFG_V_FRONT_PORCH(f) (f) | |
| 287 | + | |
| 288 | +/* Screen Blank Color Register */ | |
| 289 | +#define LCD_SPU_BLANKCOLOR 0x0124 | |
| 290 | +#define CFG_BLANKCOLOR_MASK 0x00FFFFFF | |
| 291 | +#define CFG_BLANKCOLOR_R_MASK 0x000000FF | |
| 292 | +#define CFG_BLANKCOLOR_G_MASK 0x0000FF00 | |
| 293 | +#define CFG_BLANKCOLOR_B_MASK 0x00FF0000 | |
| 294 | + | |
| 295 | +/* HW Cursor Color 1&2 Register */ | |
| 296 | +#define LCD_SPU_ALPHA_COLOR1 0x0128 | |
| 297 | +#define CFG_HWC_COLOR1 0x00FFFFFF | |
| 298 | +#define CFG_HWC_COLOR1_R(red) ((red)<<16) | |
| 299 | +#define CFG_HWC_COLOR1_G(green) ((green)<<8) | |
| 300 | +#define CFG_HWC_COLOR1_B(blue) (blue) | |
| 301 | +#define CFG_HWC_COLOR1_R_MASK 0x000000FF | |
| 302 | +#define CFG_HWC_COLOR1_G_MASK 0x0000FF00 | |
| 303 | +#define CFG_HWC_COLOR1_B_MASK 0x00FF0000 | |
| 304 | +#define LCD_SPU_ALPHA_COLOR2 0x012C | |
| 305 | +#define CFG_HWC_COLOR2 0x00FFFFFF | |
| 306 | +#define CFG_HWC_COLOR2_R_MASK 0x000000FF | |
| 307 | +#define CFG_HWC_COLOR2_G_MASK 0x0000FF00 | |
| 308 | +#define CFG_HWC_COLOR2_B_MASK 0x00FF0000 | |
| 309 | + | |
| 310 | +/* Video YUV Color Key Control */ | |
| 311 | +#define LCD_SPU_COLORKEY_Y 0x0130 | |
| 312 | +#define CFG_CKEY_Y2(y2) ((y2)<<24) | |
| 313 | +#define CFG_CKEY_Y2_MASK 0xFF000000 | |
| 314 | +#define CFG_CKEY_Y1(y1) ((y1)<<16) | |
| 315 | +#define CFG_CKEY_Y1_MASK 0x00FF0000 | |
| 316 | +#define CFG_CKEY_Y(y) ((y)<<8) | |
| 317 | +#define CFG_CKEY_Y_MASK 0x0000FF00 | |
| 318 | +#define CFG_ALPHA_Y(y) (y) | |
| 319 | +#define CFG_ALPHA_Y_MASK 0x000000FF | |
| 320 | +#define LCD_SPU_COLORKEY_U 0x0134 | |
| 321 | +#define CFG_CKEY_U2(u2) ((u2)<<24) | |
| 322 | +#define CFG_CKEY_U2_MASK 0xFF000000 | |
| 323 | +#define CFG_CKEY_U1(u1) ((u1)<<16) | |
| 324 | +#define CFG_CKEY_U1_MASK 0x00FF0000 | |
| 325 | +#define CFG_CKEY_U(u) ((u)<<8) | |
| 326 | +#define CFG_CKEY_U_MASK 0x0000FF00 | |
| 327 | +#define CFG_ALPHA_U(u) (u) | |
| 328 | +#define CFG_ALPHA_U_MASK 0x000000FF | |
| 329 | +#define LCD_SPU_COLORKEY_V 0x0138 | |
| 330 | +#define CFG_CKEY_V2(v2) ((v2)<<24) | |
| 331 | +#define CFG_CKEY_V2_MASK 0xFF000000 | |
| 332 | +#define CFG_CKEY_V1(v1) ((v1)<<16) | |
| 333 | +#define CFG_CKEY_V1_MASK 0x00FF0000 | |
| 334 | +#define CFG_CKEY_V(v) ((v)<<8) | |
| 335 | +#define CFG_CKEY_V_MASK 0x0000FF00 | |
| 336 | +#define CFG_ALPHA_V(v) (v) | |
| 337 | +#define CFG_ALPHA_V_MASK 0x000000FF | |
| 338 | + | |
| 339 | +/* Graphics/Video DMA color key enable bits in LCD_TV_CTRL1 */ | |
| 340 | +#define CFG_CKEY_GRA 0x2 | |
| 341 | +#define CFG_CKEY_DMA 0x1 | |
| 342 | + | |
| 343 | +/* Interlace mode enable bits in LCD_TV_CTRL1 */ | |
| 344 | +#define CFG_TV_INTERLACE_EN (1 << 22) | |
| 345 | +#define CFG_TV_NIB (1 << 0) | |
| 346 | + | |
| 347 | +#define LCD_PN_SEPXLCNT 0x013c /* MMP2 */ | |
| 348 | + | |
| 349 | +/* SPI Read Data Register */ | |
| 350 | +#define LCD_SPU_SPI_RXDATA 0x0140 | |
| 351 | + | |
| 352 | +/* Smart Panel Read Data Register */ | |
| 353 | +#define LCD_SPU_ISA_RSDATA 0x0144 | |
| 354 | +#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000FF | |
| 355 | +#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000FF00 | |
| 356 | +#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00FF0000 | |
| 357 | +#define ISA_RXDATA_16BIT_4_DATA_MASK 0xFF000000 | |
| 358 | +#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00FFFFFF | |
| 359 | + | |
| 360 | +#define LCD_SPU_DBG_ISA (0x0148) /* TTC */ | |
| 361 | +#define LCD_SPU_DMAVLD_YC (0x014C) | |
| 362 | +#define LCD_SPU_DMAVLD_UV (0x0150) | |
| 363 | +#define LCD_SPU_DMAVLD_UVSPU_GRAVLD (0x0154) | |
| 364 | + | |
| 365 | +#define LCD_READ_IOPAD (0x0148) /* MMP2*/ | |
| 366 | +#define LCD_DMAVLD_YC (0x014C) | |
| 367 | +#define LCD_DMAVLD_UV (0x0150) | |
| 368 | +#define LCD_TVGGRAVLD_HLEN (0x0154) | |
| 369 | + | |
| 370 | +/* HWC SRAM Read Data Register */ | |
| 371 | +#define LCD_SPU_HWC_RDDAT 0x0158 | |
| 372 | + | |
| 373 | +/* Gamma Table SRAM Read Data Register */ | |
| 374 | +#define LCD_SPU_GAMMA_RDDAT 0x015c | |
| 375 | +#define CFG_GAMMA_RDDAT_MASK 0x000000FF | |
| 376 | + | |
| 377 | +/* Palette Table SRAM Read Data Register */ | |
| 378 | +#define LCD_SPU_PALETTE_RDDAT 0x0160 | |
| 379 | +#define CFG_PALETTE_RDDAT_MASK 0x00FFFFFF | |
| 380 | + | |
| 381 | +#define LCD_SPU_DBG_DMATOP (0x0164) /* TTC */ | |
| 382 | +#define LCD_SPU_DBG_GRATOP (0x0168) | |
| 383 | +#define LCD_SPU_DBG_TXCTRL (0x016C) | |
| 384 | +#define LCD_SPU_DBG_SLVTOP (0x0170) | |
| 385 | +#define LCD_SPU_DBG_MUXTOP (0x0174) | |
| 386 | + | |
| 387 | +#define LCD_SLV_DBG (0x0164) /* MMP2 */ | |
| 388 | +#define LCD_TVDVLD_YC (0x0168) | |
| 389 | +#define LCD_TVDVLD_UV (0x016C) | |
| 390 | +#define LCD_TVC_RDDAT (0x0170) | |
| 391 | +#define LCD_TV_GAMMA_RDDAT (0x0174) | |
| 392 | + | |
| 393 | +/* I/O Pads Input Read Only Register */ | |
| 394 | +#define LCD_SPU_IOPAD_IN 0x0178 | |
| 395 | +#define CFG_IOPAD_IN_MASK 0x0FFFFFFF | |
| 396 | + | |
| 397 | +#define LCD_TV_PALETTE_RDDAT (0x0178) /* MMP2 */ | |
| 398 | + | |
| 399 | +/* Reserved Read Only Registers */ | |
| 400 | +#define LCD_CFG_RDREG5F 0x017C | |
| 401 | +#define IRE_FRAME_CNT_MASK 0x000000C0 | |
| 402 | +#define IPE_FRAME_CNT_MASK 0x00000030 | |
| 403 | +#define GRA_FRAME_CNT_MASK 0x0000000C /* Graphic */ | |
| 404 | +#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */ | |
| 405 | + | |
| 406 | +#define LCD_FRAME_CNT (0x017C) /* MMP2 */ | |
| 407 | + | |
| 408 | +/* SPI Control Register. */ | |
| 409 | +#define LCD_SPU_SPI_CTRL 0x0180 | |
| 410 | +#define CFG_SCLKCNT(div) ((div)<<24) /* 0xFF~0x2 */ | |
| 411 | +#define CFG_SCLKCNT_MASK 0xFF000000 | |
| 412 | +#define CFG_RXBITS(rx) (((rx) - 1)<<16) /* 0x1F~0x1 */ | |
| 413 | +#define CFG_RXBITS_MASK 0x00FF0000 | |
| 414 | +#define CFG_TXBITS(tx) (((tx) - 1)<<8) /* 0x1F~0x1 */ | |
| 415 | +#define CFG_TXBITS_MASK 0x0000FF00 | |
| 416 | +#define CFG_CLKINV(clk) ((clk)<<7) | |
| 417 | +#define CFG_CLKINV_MASK 0x00000080 | |
| 418 | +#define CFG_KEEPXFER(transfer) ((transfer)<<6) | |
| 419 | +#define CFG_KEEPXFER_MASK 0x00000040 | |
| 420 | +#define CFG_RXBITSTO0(rx) ((rx)<<5) | |
| 421 | +#define CFG_RXBITSTO0_MASK 0x00000020 | |
| 422 | +#define CFG_TXBITSTO0(tx) ((tx)<<4) | |
| 423 | +#define CFG_TXBITSTO0_MASK 0x00000010 | |
| 424 | +#define CFG_SPI_ENA(spi) ((spi)<<3) | |
| 425 | +#define CFG_SPI_ENA_MASK 0x00000008 | |
| 426 | +#define CFG_SPI_SEL(spi) ((spi)<<2) | |
| 427 | +#define CFG_SPI_SEL_MASK 0x00000004 | |
| 428 | +#define CFG_SPI_3W4WB(wire) ((wire)<<1) | |
| 429 | +#define CFG_SPI_3W4WB_MASK 0x00000002 | |
| 430 | +#define CFG_SPI_START(start) (start) | |
| 431 | +#define CFG_SPI_START_MASK 0x00000001 | |
| 432 | + | |
| 433 | +/* SPI Tx Data Register */ | |
| 434 | +#define LCD_SPU_SPI_TXDATA 0x0184 | |
| 435 | + | |
| 436 | +/* | |
| 437 | + 1. Smart Pannel 8-bit Bus Control Register. | |
| 438 | + 2. AHB Slave Path Data Port Register | |
| 439 | +*/ | |
| 440 | +#define LCD_SPU_SMPN_CTRL 0x0188 | |
| 441 | + | |
| 442 | +/* DMA Control 0 Register */ | |
| 443 | +#define LCD_SPU_DMA_CTRL0 0x0190 | |
| 444 | +#define CFG_NOBLENDING(nb) ((nb)<<31) | |
| 445 | +#define CFG_NOBLENDING_MASK 0x80000000 | |
| 446 | +#define CFG_GAMMA_ENA(gn) ((gn)<<30) | |
| 447 | +#define CFG_GAMMA_ENA_MASK 0x40000000 | |
| 448 | +#define CFG_CBSH_ENA(cn) ((cn)<<29) | |
| 449 | +#define CFG_CBSH_ENA_MASK 0x20000000 | |
| 450 | +#define CFG_PALETTE_ENA(pn) ((pn)<<28) | |
| 451 | +#define CFG_PALETTE_ENA_MASK 0x10000000 | |
| 452 | +#define CFG_ARBFAST_ENA(an) ((an)<<27) | |
| 453 | +#define CFG_ARBFAST_ENA_MASK 0x08000000 | |
| 454 | +#define CFG_HWC_1BITMOD(mode) ((mode)<<26) | |
| 455 | +#define CFG_HWC_1BITMOD_MASK 0x04000000 | |
| 456 | +#define CFG_HWC_1BITENA(mn) ((mn)<<25) | |
| 457 | +#define CFG_HWC_1BITENA_MASK 0x02000000 | |
| 458 | +#define CFG_HWC_ENA(cn) ((cn)<<24) | |
| 459 | +#define CFG_HWC_ENA_MASK 0x01000000 | |
| 460 | +#define CFG_DMAFORMAT(dmaformat) ((dmaformat)<<20) | |
| 461 | +#define CFG_DMAFORMAT_MASK 0x00F00000 | |
| 462 | +#define CFG_GRAFORMAT(graformat) ((graformat)<<16) | |
| 463 | +#define CFG_GRAFORMAT_MASK 0x000F0000 | |
| 464 | +/* for graphic part */ | |
| 465 | +#define CFG_GRA_FTOGGLE(toggle) ((toggle)<<15) | |
| 466 | +#define CFG_GRA_FTOGGLE_MASK 0x00008000 | |
| 467 | +#define CFG_GRA_HSMOOTH(smooth) ((smooth)<<14) | |
| 468 | +#define CFG_GRA_HSMOOTH_MASK 0x00004000 | |
| 469 | +#define CFG_GRA_TSTMODE(test) ((test)<<13) | |
| 470 | +#define CFG_GRA_TSTMODE_MASK 0x00002000 | |
| 471 | +#define CFG_GRA_SWAPRB(swap) ((swap)<<12) | |
| 472 | +#define CFG_GRA_SWAPRB_MASK 0x00001000 | |
| 473 | +#define CFG_GRA_SWAPUV(swap) ((swap)<<11) | |
| 474 | +#define CFG_GRA_SWAPUV_MASK 0x00000800 | |
| 475 | +#define CFG_GRA_SWAPYU(swap) ((swap)<<10) | |
| 476 | +#define CFG_GRA_SWAPYU_MASK 0x00000400 | |
| 477 | +#define CFG_GRA_SWAP_MASK 0x00001C00 | |
| 478 | +#define CFG_YUV2RGB_GRA(cvrt) ((cvrt)<<9) | |
| 479 | +#define CFG_YUV2RGB_GRA_MASK 0x00000200 | |
| 480 | +#define CFG_GRA_ENA(gra) ((gra)<<8) | |
| 481 | +#define CFG_GRA_ENA_MASK 0x00000100 | |
| 482 | +#define dma0_gfx_masks (CFG_GRAFORMAT_MASK | CFG_GRA_FTOGGLE_MASK | \ | |
| 483 | + CFG_GRA_HSMOOTH_MASK | CFG_GRA_TSTMODE_MASK | CFG_GRA_SWAP_MASK | \ | |
| 484 | + CFG_YUV2RGB_GRA_MASK | CFG_GRA_ENA_MASK) | |
| 485 | +/* for video part */ | |
| 486 | +#define CFG_DMA_FTOGGLE(toggle) ((toggle)<<7) | |
| 487 | +#define CFG_DMA_FTOGGLE_MASK 0x00000080 | |
| 488 | +#define CFG_DMA_HSMOOTH(smooth) ((smooth)<<6) | |
| 489 | +#define CFG_DMA_HSMOOTH_MASK 0x00000040 | |
| 490 | +#define CFG_DMA_TSTMODE(test) ((test)<<5) | |
| 491 | +#define CFG_DMA_TSTMODE_MASK 0x00000020 | |
| 492 | +#define CFG_DMA_SWAPRB(swap) ((swap)<<4) | |
| 493 | +#define CFG_DMA_SWAPRB_MASK 0x00000010 | |
| 494 | +#define CFG_DMA_SWAPUV(swap) ((swap)<<3) | |
| 495 | +#define CFG_DMA_SWAPUV_MASK 0x00000008 | |
| 496 | +#define CFG_DMA_SWAPYU(swap) ((swap)<<2) | |
| 497 | +#define CFG_DMA_SWAPYU_MASK 0x00000004 | |
| 498 | +#define CFG_DMA_SWAP_MASK 0x0000001C | |
| 499 | +#define CFG_YUV2RGB_DMA(cvrt) ((cvrt)<<1) | |
| 500 | +#define CFG_YUV2RGB_DMA_MASK 0x00000002 | |
| 501 | +#define CFG_DMA_ENA(video) (video) | |
| 502 | +#define CFG_DMA_ENA_MASK 0x00000001 | |
| 503 | +#define dma0_vid_masks (CFG_DMAFORMAT_MASK | CFG_DMA_FTOGGLE_MASK | \ | |
| 504 | + CFG_DMA_HSMOOTH_MASK | CFG_DMA_TSTMODE_MASK | CFG_DMA_SWAP_MASK | \ | |
| 505 | + CFG_YUV2RGB_DMA_MASK | CFG_DMA_ENA_MASK) | |
| 506 | +#define dma_palette(val) ((val ? 1 : 0) << 28) | |
| 507 | +#define dma_fmt(vid, val) ((val & 0xf) << ((vid) ? 20 : 16)) | |
| 508 | +#define dma_swaprb(vid, val) ((val ? 1 : 0) << ((vid) ? 4 : 12)) | |
| 509 | +#define dma_swapuv(vid, val) ((val ? 1 : 0) << ((vid) ? 3 : 11)) | |
| 510 | +#define dma_swapyuv(vid, val) ((val ? 1 : 0) << ((vid) ? 2 : 10)) | |
| 511 | +#define dma_csc(vid, val) ((val ? 1 : 0) << ((vid) ? 1 : 9)) | |
| 512 | +#define dma_hsmooth(vid, val) ((val ? 1 : 0) << ((vid) ? 6 : 14)) | |
| 513 | +#define dma_mask(vid) (dma_palette(1) | dma_fmt(vid, 0xf) | dma_csc(vid, 1) \ | |
| 514 | + | dma_swaprb(vid, 1) | dma_swapuv(vid, 1) | dma_swapyuv(vid, 1)) | |
| 515 | + | |
| 516 | +/* DMA Control 1 Register */ | |
| 517 | +#define LCD_SPU_DMA_CTRL1 0x0194 | |
| 518 | +#define CFG_FRAME_TRIG(trig) ((trig)<<31) | |
| 519 | +#define CFG_FRAME_TRIG_MASK 0x80000000 | |
| 520 | +#define CFG_VSYNC_TRIG(trig) ((trig)<<28) | |
| 521 | +#define CFG_VSYNC_TRIG_MASK 0x70000000 | |
| 522 | +#define CFG_VSYNC_INV(inv) ((inv)<<27) | |
| 523 | +#define CFG_VSYNC_INV_MASK 0x08000000 | |
| 524 | +#define CFG_COLOR_KEY_MODE(cmode) ((cmode)<<24) | |
| 525 | +#define CFG_COLOR_KEY_MASK 0x07000000 | |
| 526 | +#define CFG_CARRY(carry) ((carry)<<23) | |
| 527 | +#define CFG_CARRY_MASK 0x00800000 | |
| 528 | +#define CFG_LNBUF_ENA(lnbuf) ((lnbuf)<<22) | |
| 529 | +#define CFG_LNBUF_ENA_MASK 0x00400000 | |
| 530 | +#define CFG_GATED_ENA(gated) ((gated)<<21) | |
| 531 | +#define CFG_GATED_ENA_MASK 0x00200000 | |
| 532 | +#define CFG_PWRDN_ENA(power) ((power)<<20) | |
| 533 | +#define CFG_PWRDN_ENA_MASK 0x00100000 | |
| 534 | +#define CFG_DSCALE(dscale) ((dscale)<<18) | |
| 535 | +#define CFG_DSCALE_MASK 0x000C0000 | |
| 536 | +#define CFG_ALPHA_MODE(amode) ((amode)<<16) | |
| 537 | +#define CFG_ALPHA_MODE_MASK 0x00030000 | |
| 538 | +#define CFG_ALPHA(alpha) ((alpha)<<8) | |
| 539 | +#define CFG_ALPHA_MASK 0x0000FF00 | |
| 540 | +#define CFG_PXLCMD(pxlcmd) (pxlcmd) | |
| 541 | +#define CFG_PXLCMD_MASK 0x000000FF | |
| 542 | + | |
| 543 | +/* SRAM Control Register */ | |
| 544 | +#define LCD_SPU_SRAM_CTRL 0x0198 | |
| 545 | +#define CFG_SRAM_INIT_WR_RD(mode) ((mode)<<14) | |
| 546 | +#define CFG_SRAM_INIT_WR_RD_MASK 0x0000C000 | |
| 547 | +#define CFG_SRAM_ADDR_LCDID(id) ((id)<<8) | |
| 548 | +#define CFG_SRAM_ADDR_LCDID_MASK 0x00000F00 | |
| 549 | +#define CFG_SRAM_ADDR(addr) (addr) | |
| 550 | +#define CFG_SRAM_ADDR_MASK 0x000000FF | |
| 551 | + | |
| 552 | +/* SRAM Write Data Register */ | |
| 553 | +#define LCD_SPU_SRAM_WRDAT 0x019C | |
| 554 | + | |
| 555 | +/* SRAM RTC/WTC Control Register */ | |
| 556 | +#define LCD_SPU_SRAM_PARA0 0x01A0 | |
| 557 | + | |
| 558 | +/* SRAM Power Down Control Register */ | |
| 559 | +#define LCD_SPU_SRAM_PARA1 0x01A4 | |
| 560 | +#define CFG_CSB_256x32(hwc) ((hwc)<<15) /* HWC */ | |
| 561 | +#define CFG_CSB_256x32_MASK 0x00008000 | |
| 562 | +#define CFG_CSB_256x24(palette) ((palette)<<14) /* Palette */ | |
| 563 | +#define CFG_CSB_256x24_MASK 0x00004000 | |
| 564 | +#define CFG_CSB_256x8(gamma) ((gamma)<<13) /* Gamma */ | |
| 565 | +#define CFG_CSB_256x8_MASK 0x00002000 | |
| 566 | +#define CFG_PDWN256x32(pdwn) ((pdwn)<<7) /* HWC */ | |
| 567 | +#define CFG_PDWN256x32_MASK 0x00000080 | |
| 568 | +#define CFG_PDWN256x24(pdwn) ((pdwn)<<6) /* Palette */ | |
| 569 | +#define CFG_PDWN256x24_MASK 0x00000040 | |
| 570 | +#define CFG_PDWN256x8(pdwn) ((pdwn)<<5) /* Gamma */ | |
| 571 | +#define CFG_PDWN256x8_MASK 0x00000020 | |
| 572 | +#define CFG_PDWN32x32(pdwn) ((pdwn)<<3) | |
| 573 | +#define CFG_PDWN32x32_MASK 0x00000008 | |
| 574 | +#define CFG_PDWN16x66(pdwn) ((pdwn)<<2) | |
| 575 | +#define CFG_PDWN16x66_MASK 0x00000004 | |
| 576 | +#define CFG_PDWN32x66(pdwn) ((pdwn)<<1) | |
| 577 | +#define CFG_PDWN32x66_MASK 0x00000002 | |
| 578 | +#define CFG_PDWN64x66(pdwn) (pdwn) | |
| 579 | +#define CFG_PDWN64x66_MASK 0x00000001 | |
| 580 | + | |
| 581 | +/* Smart or Dumb Panel Clock Divider */ | |
| 582 | +#define LCD_CFG_SCLK_DIV 0x01A8 | |
| 583 | +#define SCLK_SRC_SEL(src) ((src)<<31) | |
| 584 | +#define SCLK_SRC_SEL_MASK 0x80000000 | |
| 585 | +#define SCLK_DISABLE (1<<28) | |
| 586 | +#define CLK_FRACDIV(frac) ((frac)<<16) | |
| 587 | +#define CLK_FRACDIV_MASK 0x0FFF0000 | |
| 588 | +#define DSI1_BITCLK_DIV(div) (div<<8) | |
| 589 | +#define DSI1_BITCLK_DIV_MASK 0x00000F00 | |
| 590 | +#define CLK_INT_DIV(div) (div) | |
| 591 | +#define CLK_INT_DIV_MASK 0x000000FF | |
| 592 | + | |
| 593 | +/* Video Contrast Register */ | |
| 594 | +#define LCD_SPU_CONTRAST 0x01AC | |
| 595 | +#define CFG_BRIGHTNESS(bright) ((bright)<<16) | |
| 596 | +#define CFG_BRIGHTNESS_MASK 0xFFFF0000 | |
| 597 | +#define CFG_CONTRAST(contrast) (contrast) | |
| 598 | +#define CFG_CONTRAST_MASK 0x0000FFFF | |
| 599 | + | |
| 600 | +/* Video Saturation Register */ | |
| 601 | +#define LCD_SPU_SATURATION 0x01B0 | |
| 602 | +#define CFG_C_MULTS(mult) ((mult)<<16) | |
| 603 | +#define CFG_C_MULTS_MASK 0xFFFF0000 | |
| 604 | +#define CFG_SATURATION(sat) (sat) | |
| 605 | +#define CFG_SATURATION_MASK 0x0000FFFF | |
| 606 | + | |
| 607 | +/* Video Hue Adjust Register */ | |
| 608 | +#define LCD_SPU_CBSH_HUE 0x01B4 | |
| 609 | +#define CFG_SIN0(sin0) ((sin0)<<16) | |
| 610 | +#define CFG_SIN0_MASK 0xFFFF0000 | |
| 611 | +#define CFG_COS0(con0) (con0) | |
| 612 | +#define CFG_COS0_MASK 0x0000FFFF | |
| 613 | + | |
| 614 | +/* Dump LCD Panel Control Register */ | |
| 615 | +#define LCD_SPU_DUMB_CTRL 0x01B8 | |
| 616 | +#define CFG_DUMBMODE(mode) ((mode)<<28) | |
| 617 | +#define CFG_DUMBMODE_MASK 0xF0000000 | |
| 618 | +#define CFG_LCDGPIO_O(data) ((data)<<20) | |
| 619 | +#define CFG_LCDGPIO_O_MASK 0x0FF00000 | |
| 620 | +#define CFG_LCDGPIO_ENA(gpio) ((gpio)<<12) | |
| 621 | +#define CFG_LCDGPIO_ENA_MASK 0x000FF000 | |
| 622 | +#define CFG_BIAS_OUT(bias) ((bias)<<8) | |
| 623 | +#define CFG_BIAS_OUT_MASK 0x00000100 | |
| 624 | +#define CFG_REVERSE_RGB(RGB) ((RGB)<<7) | |
| 625 | +#define CFG_REVERSE_RGB_MASK 0x00000080 | |
| 626 | +#define CFG_INV_COMPBLANK(blank) ((blank)<<6) | |
| 627 | +#define CFG_INV_COMPBLANK_MASK 0x00000040 | |
| 628 | +#define CFG_INV_COMPSYNC(sync) ((sync)<<5) | |
| 629 | +#define CFG_INV_COMPSYNC_MASK 0x00000020 | |
| 630 | +#define CFG_INV_HENA(hena) ((hena)<<4) | |
| 631 | +#define CFG_INV_HENA_MASK 0x00000010 | |
| 632 | +#define CFG_INV_VSYNC(vsync) ((vsync)<<3) | |
| 633 | +#define CFG_INV_VSYNC_MASK 0x00000008 | |
| 634 | +#define CFG_INV_HSYNC(hsync) ((hsync)<<2) | |
| 635 | +#define CFG_INV_HSYNC_MASK 0x00000004 | |
| 636 | +#define CFG_INV_PCLK(pclk) ((pclk)<<1) | |
| 637 | +#define CFG_INV_PCLK_MASK 0x00000002 | |
| 638 | +#define CFG_DUMB_ENA(dumb) (dumb) | |
| 639 | +#define CFG_DUMB_ENA_MASK 0x00000001 | |
| 640 | + | |
| 641 | +/* LCD I/O Pads Control Register */ | |
| 642 | +#define SPU_IOPAD_CONTROL 0x01BC | |
| 643 | +#define CFG_GRA_VM_ENA(vm) ((vm)<<15) | |
| 644 | +#define CFG_GRA_VM_ENA_MASK 0x00008000 | |
| 645 | +#define CFG_DMA_VM_ENA(vm) ((vm)<<13) | |
| 646 | +#define CFG_DMA_VM_ENA_MASK 0x00002000 | |
| 647 | +#define CFG_CMD_VM_ENA(vm) ((vm)<<12) | |
| 648 | +#define CFG_CMD_VM_ENA_MASK 0x00001000 | |
| 649 | +#define CFG_CSC(csc) ((csc)<<8) | |
| 650 | +#define CFG_CSC_MASK 0x00000300 | |
| 651 | +#define CFG_BOUNDARY(size) ((size)<<5) | |
| 652 | +#define CFG_BOUNDARY_MASK 0x00000020 | |
| 653 | +#define CFG_BURST(len) ((len)<<4) | |
| 654 | +#define CFG_BURST_MASK 0x00000010 | |
| 655 | +#define CFG_IOPADMODE(iopad) (iopad) | |
| 656 | +#define CFG_IOPADMODE_MASK 0x0000000F | |
| 657 | + | |
| 658 | +/* LCD Interrupt Control Register */ | |
| 659 | +#define SPU_IRQ_ENA 0x01C0 | |
| 660 | +#define DMA_FRAME_IRQ0_ENA(irq) ((irq)<<31) | |
| 661 | +#define DMA_FRAME_IRQ0_ENA_MASK 0x80000000 | |
| 662 | +#define DMA_FRAME_IRQ1_ENA(irq) ((irq)<<30) | |
| 663 | +#define DMA_FRAME_IRQ1_ENA_MASK 0x40000000 | |
| 664 | +#define DMA_FF_UNDERFLOW_ENA(ff) ((ff)<<29) | |
| 665 | +#define DMA_FF_UNDERFLOW_ENA_MASK 0x20000000 | |
| 666 | +#define AXI_BUS_ERROR_IRQ_ENA(irq) ((irq)<<28) | |
| 667 | +#define AXI_BUS_ERROR_IRQ_ENA_MASK 0x10000000 | |
| 668 | +#define GRA_FRAME_IRQ0_ENA(irq) ((irq)<<27) | |
| 669 | +#define GRA_FRAME_IRQ0_ENA_MASK 0x08000000 | |
| 670 | +#define GRA_FRAME_IRQ1_ENA(irq) ((irq)<<26) | |
| 671 | +#define GRA_FRAME_IRQ1_ENA_MASK 0x04000000 | |
| 672 | +#define GRA_FF_UNDERFLOW_ENA(ff) ((ff)<<25) | |
| 673 | +#define GRA_FF_UNDERFLOW_ENA_MASK 0x02000000 | |
| 674 | +#define VSYNC_IRQ_ENA(vsync_irq) ((vsync_irq)<<23) | |
| 675 | +#define VSYNC_IRQ_ENA_MASK 0x00800000 | |
| 676 | +#define DUMB_FRAMEDONE_ENA(fdone) ((fdone)<<22) | |
| 677 | +#define DUMB_FRAMEDONE_ENA_MASK 0x00400000 | |
| 678 | +#define TWC_FRAMEDONE_ENA(fdone) ((fdone)<<21) | |
| 679 | +#define TWC_FRAMEDONE_ENA_MASK 0x00200000 | |
| 680 | +#define HWC_FRAMEDONE_ENA(fdone) ((fdone)<<20) | |
| 681 | +#define HWC_FRAMEDONE_ENA_MASK 0x00100000 | |
| 682 | +#define SLV_IRQ_ENA(irq) ((irq)<<19) | |
| 683 | +#define SLV_IRQ_ENA_MASK 0x00080000 | |
| 684 | +#define SPI_IRQ_ENA(irq) ((irq)<<18) | |
| 685 | +#define SPI_IRQ_ENA_MASK 0x00040000 | |
| 686 | +#define PWRDN_IRQ_ENA(irq) ((irq)<<17) | |
| 687 | +#define PWRDN_IRQ_ENA_MASK 0x00020000 | |
| 688 | +#define AXI_LATENCY_TOO_LONG_IRQ_ENA(irq) ((irq)<<16) | |
| 689 | +#define AXI_LATENCY_TOO_LONG_IRQ_ENA_MASK 0x00010000 | |
| 690 | +#define CLEAN_SPU_IRQ_ISR(irq) (irq) | |
| 691 | +#define CLEAN_SPU_IRQ_ISR_MASK 0x0000FFFF | |
| 692 | +#define TV_DMA_FRAME_IRQ0_ENA(irq) ((irq)<<15) | |
| 693 | +#define TV_DMA_FRAME_IRQ0_ENA_MASK 0x00008000 | |
| 694 | +#define TV_DMA_FRAME_IRQ1_ENA(irq) ((irq)<<14) | |
| 695 | +#define TV_DMA_FRAME_IRQ1_ENA_MASK 0x00004000 | |
| 696 | +#define TV_DMA_FF_UNDERFLOW_ENA(unerrun) ((unerrun)<<13) | |
| 697 | +#define TV_DMA_FF_UNDERFLOW_ENA_MASK 0x00002000 | |
| 698 | +#define TVSYNC_IRQ_ENA(irq) ((irq)<<12) | |
| 699 | +#define TVSYNC_IRQ_ENA_MASK 0x00001000 | |
| 700 | +#define TV_FRAME_IRQ0_ENA(irq) ((irq)<<11) | |
| 701 | +#define TV_FRAME_IRQ0_ENA_MASK 0x00000800 | |
| 702 | +#define TV_FRAME_IRQ1_ENA(irq) ((irq)<<10) | |
| 703 | +#define TV_FRAME_IRQ1_ENA_MASK 0x00000400 | |
| 704 | +#define TV_GRA_FF_UNDERFLOW_ENA(unerrun) ((unerrun)<<9) | |
| 705 | +#define TV_GRA_FF_UNDERFLOW_ENA_MASK 0x00000200 | |
| 706 | +#define TV_FRAMEDONE_ENA(irq) ((irq)<<8) | |
| 707 | +#define TV_FRAMEDONE_ENA_MASK 0x00000100 | |
| 708 | + | |
| 709 | +/* FIXME - JUST GUESS */ | |
| 710 | +#define PN2_DMA_FRAME_IRQ0_ENA(irq) ((irq)<<7) | |
| 711 | +#define PN2_DMA_FRAME_IRQ0_ENA_MASK 0x00000080 | |
| 712 | +#define PN2_DMA_FRAME_IRQ1_ENA(irq) ((irq)<<6) | |
| 713 | +#define PN2_DMA_FRAME_IRQ1_ENA_MASK 0x00000040 | |
| 714 | +#define PN2_DMA_FF_UNDERFLOW_ENA(ff) ((ff)<<5) | |
| 715 | +#define PN2_DMA_FF_UNDERFLOW_ENA_MASK 0x00000020 | |
| 716 | +#define PN2_GRA_FRAME_IRQ0_ENA(irq) ((irq)<<3) | |
| 717 | +#define PN2_GRA_FRAME_IRQ0_ENA_MASK 0x00000008 | |
| 718 | +#define PN2_GRA_FRAME_IRQ1_ENA(irq) ((irq)<<2) | |
| 719 | +#define PN2_GRA_FRAME_IRQ1_ENA_MASK 0x04000004 | |
| 720 | +#define PN2_GRA_FF_UNDERFLOW_ENA(ff) ((ff)<<1) | |
| 721 | +#define PN2_GRA_FF_UNDERFLOW_ENA_MASK 0x00000002 | |
| 722 | +#define PN2_VSYNC_IRQ_ENA(irq) ((irq)<<0) | |
| 723 | +#define PN2_SYNC_IRQ_ENA_MASK 0x00000001 | |
| 724 | + | |
| 725 | +#define gf0_imask(id) ((id) ? (((id) & 1) ? TV_FRAME_IRQ0_ENA_MASK \ | |
| 726 | + : PN2_GRA_FRAME_IRQ0_ENA_MASK) : GRA_FRAME_IRQ0_ENA_MASK) | |
| 727 | +#define gf1_imask(id) ((id) ? (((id) & 1) ? TV_FRAME_IRQ1_ENA_MASK \ | |
| 728 | + : PN2_GRA_FRAME_IRQ1_ENA_MASK) : GRA_FRAME_IRQ1_ENA_MASK) | |
| 729 | +#define vsync_imask(id) ((id) ? (((id) & 1) ? TVSYNC_IRQ_ENA_MASK \ | |
| 730 | + : PN2_SYNC_IRQ_ENA_MASK) : VSYNC_IRQ_ENA_MASK) | |
| 731 | +#define vsync_imasks (vsync_imask(0) | vsync_imask(1)) | |
| 732 | + | |
| 733 | +#define display_done_imask(id) ((id) ? (((id) & 1) ? TV_FRAMEDONE_ENA_MASK\ | |
| 734 | + : (PN2_DMA_FRAME_IRQ0_ENA_MASK | PN2_DMA_FRAME_IRQ1_ENA_MASK))\ | |
| 735 | + : DUMB_FRAMEDONE_ENA_MASK) | |
| 736 | + | |
| 737 | +#define display_done_imasks (display_done_imask(0) | display_done_imask(1)) | |
| 738 | + | |
| 739 | +#define vf0_imask(id) ((id) ? (((id) & 1) ? TV_DMA_FRAME_IRQ0_ENA_MASK \ | |
| 740 | + : PN2_DMA_FRAME_IRQ0_ENA_MASK) : DMA_FRAME_IRQ0_ENA_MASK) | |
| 741 | +#define vf1_imask(id) ((id) ? (((id) & 1) ? TV_DMA_FRAME_IRQ1_ENA_MASK \ | |
| 742 | + : PN2_DMA_FRAME_IRQ1_ENA_MASK) : DMA_FRAME_IRQ1_ENA_MASK) | |
| 743 | + | |
| 744 | +#define gfx_imasks (gf0_imask(0) | gf1_imask(0) | gf0_imask(1) | \ | |
| 745 | + gf1_imask(1)) | |
| 746 | +#define vid_imasks (vf0_imask(0) | vf1_imask(0) | vf0_imask(1) | \ | |
| 747 | + vf1_imask(1)) | |
| 748 | +#define vid_imask(id) (display_done_imask(id)) | |
| 749 | + | |
| 750 | +#define pn1_imasks (gf0_imask(0) | gf1_imask(0) | vsync_imask(0) | \ | |
| 751 | + display_done_imask(0) | vf0_imask(0) | vf1_imask(0)) | |
| 752 | +#define tv_imasks (gf0_imask(1) | gf1_imask(1) | vsync_imask(1) | \ | |
| 753 | + display_done_imask(1) | vf0_imask(1) | vf1_imask(1)) | |
| 754 | +#define path_imasks(id) ((id) ? (tv_imasks) : (pn1_imasks)) | |
| 755 | + | |
| 756 | +/* error indications */ | |
| 757 | +#define vid_udflow_imask(id) ((id) ? (((id) & 1) ? \ | |
| 758 | + (TV_DMA_FF_UNDERFLOW_ENA_MASK) : (PN2_DMA_FF_UNDERFLOW_ENA_MASK)) : \ | |
| 759 | + (DMA_FF_UNDERFLOW_ENA_MASK)) | |
| 760 | +#define gfx_udflow_imask(id) ((id) ? (((id) & 1) ? \ | |
| 761 | + (TV_GRA_FF_UNDERFLOW_ENA_MASK) : (PN2_GRA_FF_UNDERFLOW_ENA_MASK)) : \ | |
| 762 | + (GRA_FF_UNDERFLOW_ENA_MASK)) | |
| 763 | + | |
| 764 | +#define err_imask(id) (vid_udflow_imask(id) | gfx_udflow_imask(id) | \ | |
| 765 | + AXI_BUS_ERROR_IRQ_ENA_MASK | AXI_LATENCY_TOO_LONG_IRQ_ENA_MASK) | |
| 766 | +#define err_imasks (err_imask(0) | err_imask(1) | err_imask(2)) | |
| 767 | +/* LCD Interrupt Status Register */ | |
| 768 | +#define SPU_IRQ_ISR 0x01C4 | |
| 769 | +#define DMA_FRAME_IRQ0(irq) ((irq)<<31) | |
| 770 | +#define DMA_FRAME_IRQ0_MASK 0x80000000 | |
| 771 | +#define DMA_FRAME_IRQ1(irq) ((irq)<<30) | |
| 772 | +#define DMA_FRAME_IRQ1_MASK 0x40000000 | |
| 773 | +#define DMA_FF_UNDERFLOW(ff) ((ff)<<29) | |
| 774 | +#define DMA_FF_UNDERFLOW_MASK 0x20000000 | |
| 775 | +#define AXI_BUS_ERROR_IRQ(irq) ((irq)<<28) | |
| 776 | +#define AXI_BUS_ERROR_IRQ_MASK 0x10000000 | |
| 777 | +#define GRA_FRAME_IRQ0(irq) ((irq)<<27) | |
| 778 | +#define GRA_FRAME_IRQ0_MASK 0x08000000 | |
| 779 | +#define GRA_FRAME_IRQ1(irq) ((irq)<<26) | |
| 780 | +#define GRA_FRAME_IRQ1_MASK 0x04000000 | |
| 781 | +#define GRA_FF_UNDERFLOW(ff) ((ff)<<25) | |
| 782 | +#define GRA_FF_UNDERFLOW_MASK 0x02000000 | |
| 783 | +#define VSYNC_IRQ(vsync_irq) ((vsync_irq)<<23) | |
| 784 | +#define VSYNC_IRQ_MASK 0x00800000 | |
| 785 | +#define DUMB_FRAMEDONE(fdone) ((fdone)<<22) | |
| 786 | +#define DUMB_FRAMEDONE_MASK 0x00400000 | |
| 787 | +#define TWC_FRAMEDONE(fdone) ((fdone)<<21) | |
| 788 | +#define TWC_FRAMEDONE_MASK 0x00200000 | |
| 789 | +#define HWC_FRAMEDONE(fdone) ((fdone)<<20) | |
| 790 | +#define HWC_FRAMEDONE_MASK 0x00100000 | |
| 791 | +#define SLV_IRQ(irq) ((irq)<<19) | |
| 792 | +#define SLV_IRQ_MASK 0x00080000 | |
| 793 | +#define SPI_IRQ(irq) ((irq)<<18) | |
| 794 | +#define SPI_IRQ_MASK 0x00040000 | |
| 795 | +#define PWRDN_IRQ(irq) ((irq)<<17) | |
| 796 | +#define PWRDN_IRQ_MASK 0x00020000 | |
| 797 | +#define AXI_LATENCY_TOO_LONGR_IRQ(irq) ((irq)<<16) | |
| 798 | +#define AXI_LATENCY_TOO_LONGR_IRQ_MASK 0x00010000 | |
| 799 | +#define TV_DMA_FRAME_IRQ0(irq) ((irq)<<15) | |
| 800 | +#define TV_DMA_FRAME_IRQ0_MASK 0x00008000 | |
| 801 | +#define TV_DMA_FRAME_IRQ1(irq) ((irq)<<14) | |
| 802 | +#define TV_DMA_FRAME_IRQ1_MASK 0x00004000 | |
| 803 | +#define TV_DMA_FF_UNDERFLOW(unerrun) ((unerrun)<<13) | |
| 804 | +#define TV_DMA_FF_UNDERFLOW_MASK 0x00002000 | |
| 805 | +#define TVSYNC_IRQ(irq) ((irq)<<12) | |
| 806 | +#define TVSYNC_IRQ_MASK 0x00001000 | |
| 807 | +#define TV_FRAME_IRQ0(irq) ((irq)<<11) | |
| 808 | +#define TV_FRAME_IRQ0_MASK 0x00000800 | |
| 809 | +#define TV_FRAME_IRQ1(irq) ((irq)<<10) | |
| 810 | +#define TV_FRAME_IRQ1_MASK 0x00000400 | |
| 811 | +#define TV_GRA_FF_UNDERFLOW(unerrun) ((unerrun)<<9) | |
| 812 | +#define TV_GRA_FF_UNDERFLOW_MASK 0x00000200 | |
| 813 | +#define PN2_DMA_FRAME_IRQ0(irq) ((irq)<<7) | |
| 814 | +#define PN2_DMA_FRAME_IRQ0_MASK 0x00000080 | |
| 815 | +#define PN2_DMA_FRAME_IRQ1(irq) ((irq)<<6) | |
| 816 | +#define PN2_DMA_FRAME_IRQ1_MASK 0x00000040 | |
| 817 | +#define PN2_DMA_FF_UNDERFLOW(ff) ((ff)<<5) | |
| 818 | +#define PN2_DMA_FF_UNDERFLOW_MASK 0x00000020 | |
| 819 | +#define PN2_GRA_FRAME_IRQ0(irq) ((irq)<<3) | |
| 820 | +#define PN2_GRA_FRAME_IRQ0_MASK 0x00000008 | |
| 821 | +#define PN2_GRA_FRAME_IRQ1(irq) ((irq)<<2) | |
| 822 | +#define PN2_GRA_FRAME_IRQ1_MASK 0x04000004 | |
| 823 | +#define PN2_GRA_FF_UNDERFLOW(ff) ((ff)<<1) | |
| 824 | +#define PN2_GRA_FF_UNDERFLOW_MASK 0x00000002 | |
| 825 | +#define PN2_VSYNC_IRQ(irq) ((irq)<<0) | |
| 826 | +#define PN2_SYNC_IRQ_MASK 0x00000001 | |
| 827 | + | |
| 828 | +/* LCD FIFO Depth register */ | |
| 829 | +#define LCD_FIFO_DEPTH 0x01c8 | |
| 830 | +#define VIDEO_FIFO(fi) ((fi) << 0) | |
| 831 | +#define VIDEO_FIFO_MASK 0x00000003 | |
| 832 | +#define GRAPHIC_FIFO(fi) ((fi) << 2) | |
| 833 | +#define GRAPHIC_FIFO_MASK 0x0000000c | |
| 834 | + | |
| 835 | +/* read-only */ | |
| 836 | +#define DMA_FRAME_IRQ0_LEVEL_MASK 0x00008000 | |
| 837 | +#define DMA_FRAME_IRQ1_LEVEL_MASK 0x00004000 | |
| 838 | +#define DMA_FRAME_CNT_ISR_MASK 0x00003000 | |
| 839 | +#define GRA_FRAME_IRQ0_LEVEL_MASK 0x00000800 | |
| 840 | +#define GRA_FRAME_IRQ1_LEVEL_MASK 0x00000400 | |
| 841 | +#define GRA_FRAME_CNT_ISR_MASK 0x00000300 | |
| 842 | +#define VSYNC_IRQ_LEVEL_MASK 0x00000080 | |
| 843 | +#define DUMB_FRAMEDONE_LEVEL_MASK 0x00000040 | |
| 844 | +#define TWC_FRAMEDONE_LEVEL_MASK 0x00000020 | |
| 845 | +#define HWC_FRAMEDONE_LEVEL_MASK 0x00000010 | |
| 846 | +#define SLV_FF_EMPTY_MASK 0x00000008 | |
| 847 | +#define DMA_FF_ALLEMPTY_MASK 0x00000004 | |
| 848 | +#define GRA_FF_ALLEMPTY_MASK 0x00000002 | |
| 849 | +#define PWRDN_IRQ_LEVEL_MASK 0x00000001 | |
| 850 | + | |
| 851 | +/* 32 bit LCD Interrupt Reset Status*/ | |
| 852 | +#define SPU_IRQ_RSR (0x01C8) | |
| 853 | +/* 32 bit Panel Path Graphic Partial Display Horizontal Control Register*/ | |
| 854 | +#define LCD_GRA_CUTHPXL (0x01CC) | |
| 855 | +/* 32 bit Panel Path Graphic Partial Display Vertical Control Register*/ | |
| 856 | +#define LCD_GRA_CUTVLN (0x01D0) | |
| 857 | +/* 32 bit TV Path Graphic Partial Display Horizontal Control Register*/ | |
| 858 | +#define LCD_TVG_CUTHPXL (0x01D4) | |
| 859 | +/* 32 bit TV Path Graphic Partial Display Vertical Control Register*/ | |
| 860 | +#define LCD_TVG_CUTVLN (0x01D8) | |
| 861 | +/* 32 bit LCD Global Control Register*/ | |
| 862 | +#define LCD_TOP_CTRL (0x01DC) | |
| 863 | +/* 32 bit LCD SQU Line Buffer Control Register 1*/ | |
| 864 | +#define LCD_SQULN1_CTRL (0x01E0) | |
| 865 | +/* 32 bit LCD SQU Line Buffer Control Register 2*/ | |
| 866 | +#define LCD_SQULN2_CTRL (0x01E4) | |
| 867 | +#define squln_ctrl(id) ((id) ? (((id) & 1) ? LCD_SQULN2_CTRL : \ | |
| 868 | + LCD_PN2_SQULN1_CTRL) : LCD_SQULN1_CTRL) | |
| 869 | + | |
| 870 | +/* 32 bit LCD Mixed Overlay Control Register */ | |
| 871 | +#define LCD_AFA_ALL2ONE (0x01E8) | |
| 872 | + | |
| 873 | +#define LCD_PN2_SCLK_DIV (0x01EC) | |
| 874 | +#define LCD_PN2_TCLK_DIV (0x01F0) | |
| 875 | +#define LCD_LVDS_SCLK_DIV_WR (0x01F4) | |
| 876 | +#define LCD_LVDS_SCLK_DIV_RD (0x01FC) | |
| 877 | +#define PN2_LCD_DMA_START_ADDR_Y0 (0x0200) | |
| 878 | +#define PN2_LCD_DMA_START_ADDR_U0 (0x0204) | |
| 879 | +#define PN2_LCD_DMA_START_ADDR_V0 (0x0208) | |
| 880 | +#define PN2_LCD_DMA_START_ADDR_C0 (0x020C) | |
| 881 | +#define PN2_LCD_DMA_START_ADDR_Y1 (0x0210) | |
| 882 | +#define PN2_LCD_DMA_START_ADDR_U1 (0x0214) | |
| 883 | +#define PN2_LCD_DMA_START_ADDR_V1 (0x0218) | |
| 884 | +#define PN2_LCD_DMA_START_ADDR_C1 (0x021C) | |
| 885 | +#define PN2_LCD_DMA_PITCH_YC (0x0220) | |
| 886 | +#define PN2_LCD_DMA_PITCH_UV (0x0224) | |
| 887 | +#define PN2_LCD_DMA_OVSA_HPXL_VLN (0x0228) | |
| 888 | +#define PN2_LCD_DMA_HPXL_VLN (0x022C) | |
| 889 | +#define PN2_LCD_DMAZM_HPXL_VLN (0x0230) | |
| 890 | +#define PN2_LCD_GRA_START_ADDR0 (0x0234) | |
| 891 | +#define PN2_LCD_GRA_START_ADDR1 (0x0238) | |
| 892 | +#define PN2_LCD_GRA_PITCH (0x023C) | |
| 893 | +#define PN2_LCD_GRA_OVSA_HPXL_VLN (0x0240) | |
| 894 | +#define PN2_LCD_GRA_HPXL_VLN (0x0244) | |
| 895 | +#define PN2_LCD_GRAZM_HPXL_VLN (0x0248) | |
| 896 | +#define PN2_LCD_HWC_OVSA_HPXL_VLN (0x024C) | |
| 897 | +#define PN2_LCD_HWC_HPXL_VLN (0x0250) | |
| 898 | +#define LCD_PN2_V_H_TOTAL (0x0254) | |
| 899 | +#define LCD_PN2_V_H_ACTIVE (0x0258) | |
| 900 | +#define LCD_PN2_H_PORCH (0x025C) | |
| 901 | +#define LCD_PN2_V_PORCH (0x0260) | |
| 902 | +#define LCD_PN2_BLANKCOLOR (0x0264) | |
| 903 | +#define LCD_PN2_ALPHA_COLOR1 (0x0268) | |
| 904 | +#define LCD_PN2_ALPHA_COLOR2 (0x026C) | |
| 905 | +#define LCD_PN2_COLORKEY_Y (0x0270) | |
| 906 | +#define LCD_PN2_COLORKEY_U (0x0274) | |
| 907 | +#define LCD_PN2_COLORKEY_V (0x0278) | |
| 908 | +#define LCD_PN2_SEPXLCNT (0x027C) | |
| 909 | +#define LCD_TV_V_H_TOTAL_FLD (0x0280) | |
| 910 | +#define LCD_TV_V_PORCH_FLD (0x0284) | |
| 911 | +#define LCD_TV_SEPXLCNT_FLD (0x0288) | |
| 912 | + | |
| 913 | +#define LCD_2ND_ALPHA (0x0294) | |
| 914 | +#define LCD_PN2_CONTRAST (0x0298) | |
| 915 | +#define LCD_PN2_SATURATION (0x029c) | |
| 916 | +#define LCD_PN2_CBSH_HUE (0x02a0) | |
| 917 | +#define LCD_TIMING_EXT (0x02C0) | |
| 918 | +#define LCD_PN2_LAYER_ALPHA_SEL1 (0x02c4) | |
| 919 | +#define LCD_PN2_CTRL0 (0x02C8) | |
| 920 | +#define TV_LAYER_ALPHA_SEL1 (0x02cc) | |
| 921 | +#define LCD_SMPN2_CTRL (0x02D0) | |
| 922 | +#define LCD_IO_OVERL_MAP_CTRL (0x02D4) | |
| 923 | +#define LCD_DUMB2_CTRL (0x02d8) | |
| 924 | +#define LCD_PN2_CTRL1 (0x02DC) | |
| 925 | +#define PN2_IOPAD_CONTROL (0x02E0) | |
| 926 | +#define LCD_PN2_SQULN1_CTRL (0x02E4) | |
| 927 | +#define PN2_LCD_GRA_CUTHPXL (0x02e8) | |
| 928 | +#define PN2_LCD_GRA_CUTVLN (0x02ec) | |
| 929 | +#define LCD_PN2_SQULN2_CTRL (0x02F0) | |
| 930 | +#define ALL_LAYER_ALPHA_SEL (0x02F4) | |
| 931 | + | |
| 932 | +/* pxa988 has different MASTER_CTRL from MMP3/MMP2 */ | |
| 933 | +#ifdef CONFIG_CPU_PXA988 | |
| 934 | +#define TIMING_MASTER_CONTROL (0x01F4) | |
| 935 | +#define MASTER_ENH(id) (1 << ((id) + 5)) | |
| 936 | +#define MASTER_ENV(id) (1 << ((id) + 6)) | |
| 937 | +#else | |
| 938 | +#define TIMING_MASTER_CONTROL (0x02F8) | |
| 939 | +#define MASTER_ENH(id) (1 << (id)) | |
| 940 | +#define MASTER_ENV(id) (1 << ((id) + 4)) | |
| 941 | +#endif | |
| 942 | + | |
| 943 | +#define DSI_START_SEL_SHIFT(id) (((id) << 1) + 8) | |
| 944 | +#define timing_master_config(path, dsi_id, lcd_id) \ | |
| 945 | + (MASTER_ENH(path) | MASTER_ENV(path) | \ | |
| 946 | + (((lcd_id) + ((dsi_id) << 1)) << DSI_START_SEL_SHIFT(path))) | |
| 947 | + | |
| 948 | +#define LCD_2ND_BLD_CTL (0x02Fc) | |
| 949 | +#define LVDS_SRC_MASK (3 << 30) | |
| 950 | +#define LVDS_SRC_SHIFT (30) | |
| 951 | +#define LVDS_FMT_MASK (1 << 28) | |
| 952 | +#define LVDS_FMT_SHIFT (28) | |
| 953 | + | |
| 954 | +#define CLK_SCLK (1 << 0) | |
| 955 | +#define CLK_LVDS_RD (1 << 1) | |
| 956 | +#define CLK_LVDS_WR (1 << 2) | |
| 957 | + | |
| 958 | +#define gra_partdisp_ctrl_hor(id) ((id) ? (((id) & 1) ? \ | |
| 959 | + LCD_TVG_CUTHPXL : PN2_LCD_GRA_CUTHPXL) : LCD_GRA_CUTHPXL) | |
| 960 | +#define gra_partdisp_ctrl_ver(id) ((id) ? (((id) & 1) ? \ | |
| 961 | + LCD_TVG_CUTVLN : PN2_LCD_GRA_CUTVLN) : LCD_GRA_CUTVLN) | |
| 962 | + | |
| 963 | +/* | |
| 964 | + * defined Video Memory Color format for DMA control 0 register | |
| 965 | + * DMA0 bit[23:20] | |
| 966 | + */ | |
| 967 | +#define VMODE_RGB565 0x0 | |
| 968 | +#define VMODE_RGB1555 0x1 | |
| 969 | +#define VMODE_RGB888PACKED 0x2 | |
| 970 | +#define VMODE_RGB888UNPACKED 0x3 | |
| 971 | +#define VMODE_RGBA888 0x4 | |
| 972 | +#define VMODE_YUV422PACKED 0x5 | |
| 973 | +#define VMODE_YUV422PLANAR 0x6 | |
| 974 | +#define VMODE_YUV420PLANAR 0x7 | |
| 975 | +#define VMODE_SMPNCMD 0x8 | |
| 976 | +#define VMODE_PALETTE4BIT 0x9 | |
| 977 | +#define VMODE_PALETTE8BIT 0xa | |
| 978 | +#define VMODE_RESERVED 0xb | |
| 979 | + | |
| 980 | +/* | |
| 981 | + * defined Graphic Memory Color format for DMA control 0 register | |
| 982 | + * DMA0 bit[19:16] | |
| 983 | + */ | |
| 984 | +#define GMODE_RGB565 0x0 | |
| 985 | +#define GMODE_RGB1555 0x1 | |
| 986 | +#define GMODE_RGB888PACKED 0x2 | |
| 987 | +#define GMODE_RGB888UNPACKED 0x3 | |
| 988 | +#define GMODE_RGBA888 0x4 | |
| 989 | +#define GMODE_YUV422PACKED 0x5 | |
| 990 | +#define GMODE_YUV422PLANAR 0x6 | |
| 991 | +#define GMODE_YUV420PLANAR 0x7 | |
| 992 | +#define GMODE_SMPNCMD 0x8 | |
| 993 | +#define GMODE_PALETTE4BIT 0x9 | |
| 994 | +#define GMODE_PALETTE8BIT 0xa | |
| 995 | +#define GMODE_RESERVED 0xb | |
| 996 | + | |
| 997 | +/* | |
| 998 | + * define for DMA control 1 register | |
| 999 | + */ | |
| 1000 | +#define DMA1_FRAME_TRIG 31 /* bit location */ | |
| 1001 | +#define DMA1_VSYNC_MODE 28 | |
| 1002 | +#define DMA1_VSYNC_INV 27 | |
| 1003 | +#define DMA1_CKEY 24 | |
| 1004 | +#define DMA1_CARRY 23 | |
| 1005 | +#define DMA1_LNBUF_ENA 22 | |
| 1006 | +#define DMA1_GATED_ENA 21 | |
| 1007 | +#define DMA1_PWRDN_ENA 20 | |
| 1008 | +#define DMA1_DSCALE 18 | |
| 1009 | +#define DMA1_ALPHA_MODE 16 | |
| 1010 | +#define DMA1_ALPHA 08 | |
| 1011 | +#define DMA1_PXLCMD 00 | |
| 1012 | + | |
| 1013 | +/* | |
| 1014 | + * defined for Configure Dumb Mode | |
| 1015 | + * DUMB LCD Panel bit[31:28] | |
| 1016 | + */ | |
| 1017 | +#define DUMB16_RGB565_0 0x0 | |
| 1018 | +#define DUMB16_RGB565_1 0x1 | |
| 1019 | +#define DUMB18_RGB666_0 0x2 | |
| 1020 | +#define DUMB18_RGB666_1 0x3 | |
| 1021 | +#define DUMB12_RGB444_0 0x4 | |
| 1022 | +#define DUMB12_RGB444_1 0x5 | |
| 1023 | +#define DUMB24_RGB888_0 0x6 | |
| 1024 | +#define DUMB_BLANK 0x7 | |
| 1025 | + | |
| 1026 | +/* | |
| 1027 | + * defined for Configure I/O Pin Allocation Mode | |
| 1028 | + * LCD LCD I/O Pads control register bit[3:0] | |
| 1029 | + */ | |
| 1030 | +#define IOPAD_DUMB24 0x0 | |
| 1031 | +#define IOPAD_DUMB18SPI 0x1 | |
| 1032 | +#define IOPAD_DUMB18GPIO 0x2 | |
| 1033 | +#define IOPAD_DUMB16SPI 0x3 | |
| 1034 | +#define IOPAD_DUMB16GPIO 0x4 | |
| 1035 | +#define IOPAD_DUMB12 0x5 | |
| 1036 | +#define IOPAD_SMART18SPI 0x6 | |
| 1037 | +#define IOPAD_SMART16SPI 0x7 | |
| 1038 | +#define IOPAD_SMART8BOTH 0x8 | |
| 1039 | +#define IOPAD_DUMB18_SMART8 0x9 | |
| 1040 | +#define IOPAD_DUMB16_SMART8SPI 0xa | |
| 1041 | +#define IOPAD_DUMB16_SMART8GPIO 0xb | |
| 1042 | +#define IOPAD_DUMB16_DUMB16 0xc | |
| 1043 | +#define IOPAD_SMART8_SMART8 0xc | |
| 1044 | + | |
| 1045 | +/* | |
| 1046 | + *defined for indicating boundary and cycle burst length | |
| 1047 | + */ | |
| 1048 | +#define CFG_BOUNDARY_1KB (1<<5) | |
| 1049 | +#define CFG_BOUNDARY_4KB (0<<5) | |
| 1050 | +#define CFG_CYC_BURST_LEN16 (1<<4) | |
| 1051 | +#define CFG_CYC_BURST_LEN8 (0<<4) | |
| 1052 | + | |
| 1053 | +/* | |
| 1054 | + * defined Dumb Panel Clock Divider register | |
| 1055 | + * SCLK_Source bit[31] | |
| 1056 | + */ | |
| 1057 | + /* 0: PLL clock select*/ | |
| 1058 | +#define AXI_BUS_SEL 0x80000000 | |
| 1059 | +#define CCD_CLK_SEL 0x40000000 | |
| 1060 | +#define DCON_CLK_SEL 0x20000000 | |
| 1061 | +#define ENA_CLK_INT_DIV CONFIG_FB_DOVE_CLCD_SCLK_DIV | |
| 1062 | +#define IDLE_CLK_INT_DIV 0x1 /* idle Integer Divider */ | |
| 1063 | +#define DIS_CLK_INT_DIV 0x0 /* Disable Integer Divider */ | |
| 1064 | + | |
| 1065 | +/* SRAM ID */ | |
| 1066 | +#define SRAMID_GAMMA_YR 0x0 | |
| 1067 | +#define SRAMID_GAMMA_UG 0x1 | |
| 1068 | +#define SRAMID_GAMMA_VB 0x2 | |
| 1069 | +#define SRAMID_PALATTE 0x3 | |
| 1070 | +#define SRAMID_HWC 0xf | |
| 1071 | + | |
| 1072 | +/* SRAM INIT Read/Write */ | |
| 1073 | +#define SRAMID_INIT_READ 0x0 | |
| 1074 | +#define SRAMID_INIT_WRITE 0x2 | |
| 1075 | +#define SRAMID_INIT_DEFAULT 0x3 | |
| 1076 | + | |
| 1077 | +/* | |
| 1078 | + * defined VSYNC selection mode for DMA control 1 register | |
| 1079 | + * DMA1 bit[30:28] | |
| 1080 | + */ | |
| 1081 | +#define VMODE_SMPN 0x0 | |
| 1082 | +#define VMODE_SMPNIRQ 0x1 | |
| 1083 | +#define VMODE_DUMB 0x2 | |
| 1084 | +#define VMODE_IPE 0x3 | |
| 1085 | +#define VMODE_IRE 0x4 | |
| 1086 | + | |
| 1087 | +/* | |
| 1088 | + * defined Configure Alpha and Alpha mode for DMA control 1 register | |
| 1089 | + * DMA1 bit[15:08](alpha) / bit[17:16](alpha mode) | |
| 1090 | + */ | |
| 1091 | +/* ALPHA mode */ | |
| 1092 | +#define MODE_ALPHA_DMA 0x0 | |
| 1093 | +#define MODE_ALPHA_GRA 0x1 | |
| 1094 | +#define MODE_ALPHA_CFG 0x2 | |
| 1095 | + | |
| 1096 | +/* alpha value */ | |
| 1097 | +#define ALPHA_NOGRAPHIC 0xFF /* all video, no graphic */ | |
| 1098 | +#define ALPHA_NOVIDEO 0x00 /* all graphic, no video */ | |
| 1099 | +#define ALPHA_GRAPHNVIDEO 0x0F /* Selects graphic & video */ | |
| 1100 | + | |
| 1101 | +/* | |
| 1102 | + * defined Pixel Command for DMA control 1 register | |
| 1103 | + * DMA1 bit[07:00] | |
| 1104 | + */ | |
| 1105 | +#define PIXEL_CMD 0x81 | |
| 1106 | + | |
| 1107 | +/* DSI */ | |
| 1108 | +/* DSI1 - 4 Lane Controller base */ | |
| 1109 | +#define DSI1_REGS_PHYSICAL_BASE 0xD420B800 | |
| 1110 | +/* DSI2 - 3 Lane Controller base */ | |
| 1111 | +#define DSI2_REGS_PHYSICAL_BASE 0xD420BA00 | |
| 1112 | + | |
| 1113 | +/* DSI Controller Registers */ | |
| 1114 | +struct dsi_lcd_regs { | |
| 1115 | +#define DSI_LCD1_CTRL_0 0x100 /* DSI Active Panel 1 Control register 0 */ | |
| 1116 | +#define DSI_LCD1_CTRL_1 0x104 /* DSI Active Panel 1 Control register 1 */ | |
| 1117 | + u32 ctrl0; | |
| 1118 | + u32 ctrl1; | |
| 1119 | + u32 reserved1[2]; | |
| 1120 | + | |
| 1121 | +#define DSI_LCD1_TIMING_0 0x110 /* Timing register 0 */ | |
| 1122 | +#define DSI_LCD1_TIMING_1 0x114 /* Timing register 1 */ | |
| 1123 | +#define DSI_LCD1_TIMING_2 0x118 /* Timing register 2 */ | |
| 1124 | +#define DSI_LCD1_TIMING_3 0x11C /* Timing register 3 */ | |
| 1125 | +#define DSI_LCD1_WC_0 0x120 /* Word Count register 0 */ | |
| 1126 | +#define DSI_LCD1_WC_1 0x124 /* Word Count register 1 */ | |
| 1127 | +#define DSI_LCD1_WC_2 0x128 /* Word Count register 2 */ | |
| 1128 | + u32 timing0; | |
| 1129 | + u32 timing1; | |
| 1130 | + u32 timing2; | |
| 1131 | + u32 timing3; | |
| 1132 | + u32 wc0; | |
| 1133 | + u32 wc1; | |
| 1134 | + u32 wc2; | |
| 1135 | + u32 reserved2[1]; | |
| 1136 | + u32 slot_cnt0; | |
| 1137 | + u32 slot_cnt1; | |
| 1138 | + u32 reserved3[2]; | |
| 1139 | + u32 status_0; | |
| 1140 | + u32 status_1; | |
| 1141 | + u32 status_2; | |
| 1142 | + u32 status_3; | |
| 1143 | + u32 status_4; | |
| 1144 | +}; | |
| 1145 | + | |
| 1146 | +struct dsi_regs { | |
| 1147 | +#define DSI_CTRL_0 0x000 /* DSI control register 0 */ | |
| 1148 | +#define DSI_CTRL_1 0x004 /* DSI control register 1 */ | |
| 1149 | + u32 ctrl0; | |
| 1150 | + u32 ctrl1; | |
| 1151 | + u32 reserved1[2]; | |
| 1152 | + u32 irq_status; | |
| 1153 | + u32 irq_mask; | |
| 1154 | + u32 reserved2[2]; | |
| 1155 | + | |
| 1156 | +#define DSI_CPU_CMD_0 0x020 /* DSI CPU packet command register 0 */ | |
| 1157 | +#define DSI_CPU_CMD_1 0x024 /* DSU CPU Packet Command Register 1 */ | |
| 1158 | +#define DSI_CPU_CMD_3 0x02C /* DSU CPU Packet Command Register 3 */ | |
| 1159 | +#define DSI_CPU_WDAT_0 0x030 /* DSI CUP */ | |
| 1160 | + u32 cmd0; | |
| 1161 | + u32 cmd1; | |
| 1162 | + u32 cmd2; | |
| 1163 | + u32 cmd3; | |
| 1164 | + u32 dat0; | |
| 1165 | + u32 status0; | |
| 1166 | + u32 status1; | |
| 1167 | + u32 status2; | |
| 1168 | + u32 status3; | |
| 1169 | + u32 status4; | |
| 1170 | + u32 reserved3[2]; | |
| 1171 | + | |
| 1172 | + u32 smt_cmd; | |
| 1173 | + u32 smt_ctrl0; | |
| 1174 | + u32 smt_ctrl1; | |
| 1175 | + u32 reserved4[1]; | |
| 1176 | + | |
| 1177 | + u32 rx0_status; | |
| 1178 | + | |
| 1179 | +/* Rx Packet Header - data from slave device */ | |
| 1180 | +#define DSI_RX_PKT_HDR_0 0x064 | |
| 1181 | + u32 rx0_header; | |
| 1182 | + u32 rx1_status; | |
| 1183 | + u32 rx1_header; | |
| 1184 | + u32 rx_ctrl; | |
| 1185 | + u32 rx_ctrl1; | |
| 1186 | + u32 rx2_status; | |
| 1187 | + u32 rx2_header; | |
| 1188 | + u32 reserved5[1]; | |
| 1189 | + | |
| 1190 | + u32 phy_ctrl1; | |
| 1191 | +#define DSI_PHY_CTRL_2 0x088 /* DSI DPHI Control Register 2 */ | |
| 1192 | +#define DSI_PHY_CTRL_3 0x08C /* DPHY Control Register 3 */ | |
| 1193 | + u32 phy_ctrl2; | |
| 1194 | + u32 phy_ctrl3; | |
| 1195 | + u32 phy_status0; | |
| 1196 | + u32 phy_status1; | |
| 1197 | + u32 reserved6[5]; | |
| 1198 | + u32 phy_status2; | |
| 1199 | + | |
| 1200 | +#define DSI_PHY_RCOMP_0 0x0B0 /* DPHY Rcomp Control Register */ | |
| 1201 | + u32 phy_rcomp0; | |
| 1202 | + u32 reserved7[3]; | |
| 1203 | +#define DSI_PHY_TIME_0 0x0C0 /* DPHY Timing Control Register 0 */ | |
| 1204 | +#define DSI_PHY_TIME_1 0x0C4 /* DPHY Timing Control Register 1 */ | |
| 1205 | +#define DSI_PHY_TIME_2 0x0C8 /* DPHY Timing Control Register 2 */ | |
| 1206 | +#define DSI_PHY_TIME_3 0x0CC /* DPHY Timing Control Register 3 */ | |
| 1207 | +#define DSI_PHY_TIME_4 0x0D0 /* DPHY Timing Control Register 4 */ | |
| 1208 | +#define DSI_PHY_TIME_5 0x0D4 /* DPHY Timing Control Register 5 */ | |
| 1209 | + u32 phy_timing0; | |
| 1210 | + u32 phy_timing1; | |
| 1211 | + u32 phy_timing2; | |
| 1212 | + u32 phy_timing3; | |
| 1213 | + u32 phy_code_0; | |
| 1214 | + u32 phy_code_1; | |
| 1215 | + u32 reserved8[2]; | |
| 1216 | + u32 mem_ctrl; | |
| 1217 | + u32 tx_timer; | |
| 1218 | + u32 rx_timer; | |
| 1219 | + u32 turn_timer; | |
| 1220 | + u32 reserved9[4]; | |
| 1221 | + | |
| 1222 | +#define DSI_LCD1_CTRL_0 0x100 /* DSI Active Panel 1 Control register 0 */ | |
| 1223 | +#define DSI_LCD1_CTRL_1 0x104 /* DSI Active Panel 1 Control register 1 */ | |
| 1224 | +#define DSI_LCD1_TIMING_0 0x110 /* Timing register 0 */ | |
| 1225 | +#define DSI_LCD1_TIMING_1 0x114 /* Timing register 1 */ | |
| 1226 | +#define DSI_LCD1_TIMING_2 0x118 /* Timing register 2 */ | |
| 1227 | +#define DSI_LCD1_TIMING_3 0x11C /* Timing register 3 */ | |
| 1228 | +#define DSI_LCD1_WC_0 0x120 /* Word Count register 0 */ | |
| 1229 | +#define DSI_LCD1_WC_1 0x124 /* Word Count register 1 */ | |
| 1230 | +#define DSI_LCD1_WC_2 0x128 /* Word Count register 2 */ | |
| 1231 | + struct dsi_lcd_regs lcd1; | |
| 1232 | + u32 reserved10[11]; | |
| 1233 | + struct dsi_lcd_regs lcd2; | |
| 1234 | +}; | |
| 1235 | + | |
| 1236 | +#define DSI_LCD2_CTRL_0 0x180 /* DSI Active Panel 2 Control register 0 */ | |
| 1237 | +#define DSI_LCD2_CTRL_1 0x184 /* DSI Active Panel 2 Control register 1 */ | |
| 1238 | +#define DSI_LCD2_TIMING_0 0x190 /* Timing register 0 */ | |
| 1239 | +#define DSI_LCD2_TIMING_1 0x194 /* Timing register 1 */ | |
| 1240 | +#define DSI_LCD2_TIMING_2 0x198 /* Timing register 2 */ | |
| 1241 | +#define DSI_LCD2_TIMING_3 0x19C /* Timing register 3 */ | |
| 1242 | +#define DSI_LCD2_WC_0 0x1A0 /* Word Count register 0 */ | |
| 1243 | +#define DSI_LCD2_WC_1 0x1A4 /* Word Count register 1 */ | |
| 1244 | +#define DSI_LCD2_WC_2 0x1A8 /* Word Count register 2 */ | |
| 1245 | + | |
| 1246 | +/* DSI_CTRL_0 0x0000 DSI Control Register 0 */ | |
| 1247 | +#define DSI_CTRL_0_CFG_SOFT_RST (1<<31) | |
| 1248 | +#define DSI_CTRL_0_CFG_SOFT_RST_REG (1<<30) | |
| 1249 | +#define DSI_CTRL_0_CFG_LCD1_TX_EN (1<<8) | |
| 1250 | +#define DSI_CTRL_0_CFG_LCD1_SLV (1<<4) | |
| 1251 | +#define DSI_CTRL_0_CFG_LCD1_EN (1<<0) | |
| 1252 | + | |
| 1253 | +/* DSI_CTRL_1 0x0004 DSI Control Register 1 */ | |
| 1254 | +#define DSI_CTRL_1_CFG_EOTP (1<<8) | |
| 1255 | +#define DSI_CTRL_1_CFG_RSVD (2<<4) | |
| 1256 | +#define DSI_CTRL_1_CFG_LCD2_VCH_NO_MASK (3<<2) | |
| 1257 | +#define DSI_CTRL_1_CFG_LCD2_VCH_NO_SHIFT 2 | |
| 1258 | +#define DSI_CTRL_1_CFG_LCD1_VCH_NO_MASK (3<<0) | |
| 1259 | +#define DSI_CTRL_1_CFG_LCD1_VCH_NO_SHIFT 0 | |
| 1260 | + | |
| 1261 | +/* DSI_LCD1_CTRL_1 0x0104 DSI Active Panel 1 Control Register 1 */ | |
| 1262 | +/* LCD 1 Vsync Reset Enable */ | |
| 1263 | +#define DSI_LCD1_CTRL_1_CFG_L1_VSYNC_RST_EN (1<<31) | |
| 1264 | +/* LCD 1 2K Pixel Buffer Mode Enable */ | |
| 1265 | +#define DSI_LCD1_CTRL_1_CFG_L1_M2K_EN (1<<30) | |
| 1266 | +/* Bit(s) DSI_LCD1_CTRL_1_RSRV_29_23 reserved */ | |
| 1267 | +/* Long Blanking Packet Enable */ | |
| 1268 | +#define DSI_LCD1_CTRL_1_CFG_L1_HLP_PKT_EN (1<<22) | |
| 1269 | +/* Extra Long Blanking Packet Enable */ | |
| 1270 | +#define DSI_LCD1_CTRL_1_CFG_L1_HEX_PKT_EN (1<<21) | |
| 1271 | +/* Front Porch Packet Enable */ | |
| 1272 | +#define DSI_LCD1_CTRL_1_CFG_L1_HFP_PKT_EN (1<<20) | |
| 1273 | +/* hact Packet Enable */ | |
| 1274 | +#define DSI_LCD1_CTRL_1_CFG_L1_HACT_PKT_EN (1<<19) | |
| 1275 | +/* Back Porch Packet Enable */ | |
| 1276 | +#define DSI_LCD1_CTRL_1_CFG_L1_HBP_PKT_EN (1<<18) | |
| 1277 | +/* hse Packet Enable */ | |
| 1278 | +#define DSI_LCD1_CTRL_1_CFG_L1_HSE_PKT_EN (1<<17) | |
| 1279 | +/* hsa Packet Enable */ | |
| 1280 | +#define DSI_LCD1_CTRL_1_CFG_L1_HSA_PKT_EN (1<<16) | |
| 1281 | +/* All Item Enable after Pixel Data */ | |
| 1282 | +#define DSI_LCD1_CTRL_1_CFG_L1_ALL_SLOT_EN (1<<15) | |
| 1283 | +/* Extra Long Packet Enable after Pixel Data */ | |
| 1284 | +#define DSI_LCD1_CTRL_1_CFG_L1_HEX_SLOT_EN (1<<14) | |
| 1285 | +/* Bit(s) DSI_LCD1_CTRL_1_RSRV_13_11 reserved */ | |
| 1286 | +/* Turn Around Bus at Last h Line */ | |
| 1287 | +#define DSI_LCD1_CTRL_1_CFG_L1_LAST_LINE_TURN (1<<10) | |
| 1288 | +/* Go to Low Power Every Frame */ | |
| 1289 | +#define DSI_LCD1_CTRL_1_CFG_L1_LPM_FRAME_EN (1<<9) | |
| 1290 | +/* Go to Low Power Every Line */ | |
| 1291 | +#define DSI_LCD1_CTRL_1_CFG_L1_LPM_LINE_EN (1<<8) | |
| 1292 | +/* Bit(s) DSI_LCD1_CTRL_1_RSRV_7_4 reserved */ | |
| 1293 | +/* DSI Transmission Mode for LCD 1 */ | |
| 1294 | +#define DSI_LCD1_CTRL_1_CFG_L1_BURST_MODE_SHIFT 2 | |
| 1295 | +#define DSI_LCD1_CTRL_1_CFG_L1_BURST_MODE_MASK (3<<2) | |
| 1296 | +/* LCD 1 Input Data RGB Mode for LCD 1 */ | |
| 1297 | +#define DSI_LCD2_CTRL_1_CFG_L1_RGB_TYPE_SHIFT 0 | |
| 1298 | +#define DSI_LCD2_CTRL_1_CFG_L1_RGB_TYPE_MASK (3<<2) | |
| 1299 | + | |
| 1300 | +/* DSI_PHY_CTRL_2 0x0088 DPHY Control Register 2 */ | |
| 1301 | +/* Bit(s) DSI_PHY_CTRL_2_RSRV_31_12 reserved */ | |
| 1302 | +/* DPHY LP Receiver Enable */ | |
| 1303 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_RESC_EN_MASK (0xf<<8) | |
| 1304 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_RESC_EN_SHIFT 8 | |
| 1305 | +/* DPHY Data Lane Enable */ | |
| 1306 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_MASK (0xf<<4) | |
| 1307 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_SHIFT 4 | |
| 1308 | +/* DPHY Bus Turn Around */ | |
| 1309 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_TURN_MASK (0xf) | |
| 1310 | +#define DSI_PHY_CTRL_2_CFG_CSR_LANE_TURN_SHIFT 0 | |
| 1311 | + | |
| 1312 | +/* DSI_CPU_CMD_1 0x0024 DSI CPU Packet Command Register 1 */ | |
| 1313 | +/* Bit(s) DSI_CPU_CMD_1_RSRV_31_24 reserved */ | |
| 1314 | +/* LPDT TX Enable */ | |
| 1315 | +#define DSI_CPU_CMD_1_CFG_TXLP_LPDT_MASK (0xf<<20) | |
| 1316 | +#define DSI_CPU_CMD_1_CFG_TXLP_LPDT_SHIFT 20 | |
| 1317 | +/* ULPS TX Enable */ | |
| 1318 | +#define DSI_CPU_CMD_1_CFG_TXLP_ULPS_MASK (0xf<<16) | |
| 1319 | +#define DSI_CPU_CMD_1_CFG_TXLP_ULPS_SHIFT 16 | |
| 1320 | +/* Low Power TX Trigger Code */ | |
| 1321 | +#define DSI_CPU_CMD_1_CFG_TXLP_TRIGGER_CODE_MASK (0xffff) | |
| 1322 | +#define DSI_CPU_CMD_1_CFG_TXLP_TRIGGER_CODE_SHIFT 0 | |
| 1323 | + | |
| 1324 | +/* DSI_PHY_TIME_0 0x00c0 DPHY Timing Control Register 0 */ | |
| 1325 | +/* Length of HS Exit Period in tx_clk_esc Cycles */ | |
| 1326 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_EXIT_MASK (0xff<<24) | |
| 1327 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_EXIT_SHIFT 24 | |
| 1328 | +/* DPHY HS Trail Period Length */ | |
| 1329 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_TRAIL_MASK (0xff<<16) | |
| 1330 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_TRAIL_SHIFT 16 | |
| 1331 | +/* DPHY HS Zero State Length */ | |
| 1332 | +#define DSI_PHY_TIME_0_CDG_CSR_TIME_HS_ZERO_MASK (0xff<<8) | |
| 1333 | +#define DSI_PHY_TIME_0_CDG_CSR_TIME_HS_ZERO_SHIFT 8 | |
| 1334 | +/* DPHY HS Prepare State Length */ | |
| 1335 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_PREP_MASK (0xff) | |
| 1336 | +#define DSI_PHY_TIME_0_CFG_CSR_TIME_HS_PREP_SHIFT 0 | |
| 1337 | + | |
| 1338 | +/* DSI_PHY_TIME_1 0x00c4 DPHY Timing Control Register 1 */ | |
| 1339 | +/* Time to Drive LP-00 by New Transmitter */ | |
| 1340 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GET_MASK (0xff<<24) | |
| 1341 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GET_SHIFT 24 | |
| 1342 | +/* Time to Drive LP-00 after Turn Request */ | |
| 1343 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GO_MASK (0xff<<16) | |
| 1344 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GO_SHIFT 16 | |
| 1345 | +/* DPHY HS Wakeup Period Length */ | |
| 1346 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_WAKEUP_MASK (0xffff) | |
| 1347 | +#define DSI_PHY_TIME_1_CFG_CSR_TIME_WAKEUP_SHIFT 0 | |
| 1348 | + | |
| 1349 | +/* DSI_PHY_TIME_2 0x00c8 DPHY Timing Control Register 2 */ | |
| 1350 | +/* DPHY CLK Exit Period Length */ | |
| 1351 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_EXIT_MASK (0xff<<24) | |
| 1352 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_EXIT_SHIFT 24 | |
| 1353 | +/* DPHY CLK Trail Period Length */ | |
| 1354 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_TRAIL_MASK (0xff<<16) | |
| 1355 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_TRAIL_SHIFT 16 | |
| 1356 | +/* DPHY CLK Zero State Length */ | |
| 1357 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_ZERO_MASK (0xff<<8) | |
| 1358 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_ZERO_SHIFT 8 | |
| 1359 | +/* DPHY CLK LP Length */ | |
| 1360 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_LPX_MASK (0xff) | |
| 1361 | +#define DSI_PHY_TIME_2_CFG_CSR_TIME_CK_LPX_SHIFT 0 | |
| 1362 | + | |
| 1363 | +/* DSI_PHY_TIME_3 0x00cc DPHY Timing Control Register 3 */ | |
| 1364 | +/* Bit(s) DSI_PHY_TIME_3_RSRV_31_16 reserved */ | |
| 1365 | +/* DPHY LP Length */ | |
| 1366 | +#define DSI_PHY_TIME_3_CFG_CSR_TIME_LPX_MASK (0xff<<8) | |
| 1367 | +#define DSI_PHY_TIME_3_CFG_CSR_TIME_LPX_SHIFT 8 | |
| 1368 | +/* DPHY HS req to rdy Length */ | |
| 1369 | +#define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_MASK (0xff) | |
| 1370 | +#define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_SHIFT 0 | |
| 1371 | + | |
| 1372 | +/* | |
| 1373 | + * DSI timings | |
| 1374 | + * PXA988 has diffrent ESC CLK with MMP2/MMP3 | |
| 1375 | + * it will be used in dsi_set_dphy() in pxa688_phy.c | |
| 1376 | + * as low power mode clock. | |
| 1377 | + */ | |
| 1378 | +#ifdef CONFIG_CPU_PXA988 | |
| 1379 | +#define DSI_ESC_CLK 52 /* Unit: Mhz */ | |
| 1380 | +#define DSI_ESC_CLK_T 19 /* Unit: ns */ | |
| 1381 | +#else | |
| 1382 | +#define DSI_ESC_CLK 66 /* Unit: Mhz */ | |
| 1383 | +#define DSI_ESC_CLK_T 15 /* Unit: ns */ | |
| 1384 | +#endif | |
| 1385 | + | |
| 1386 | +/* LVDS */ | |
| 1387 | +/* LVDS_PHY_CTRL */ | |
| 1388 | +#define LVDS_PHY_CTL 0x2A4 | |
| 1389 | +#define LVDS_PLL_LOCK (1 << 31) | |
| 1390 | +#define LVDS_PHY_EXT_MASK (7 << 28) | |
| 1391 | +#define LVDS_PHY_EXT_SHIFT (28) | |
| 1392 | +#define LVDS_CLK_PHASE_MASK (0x7f << 16) | |
| 1393 | +#define LVDS_CLK_PHASE_SHIFT (16) | |
| 1394 | +#define LVDS_SSC_RESET_EXT (1 << 13) | |
| 1395 | +#define LVDS_SSC_MODE_DOWN_SPREAD (1 << 12) | |
| 1396 | +#define LVDS_SSC_EN (1 << 11) | |
| 1397 | +#define LVDS_PU_PLL (1 << 10) | |
| 1398 | +#define LVDS_PU_TX (1 << 9) | |
| 1399 | +#define LVDS_PU_IVREF (1 << 8) | |
| 1400 | +#define LVDS_CLK_SEL (1 << 7) | |
| 1401 | +#define LVDS_CLK_SEL_LVDS_PCLK (1 << 7) | |
| 1402 | +#define LVDS_PD_CH_MASK (0x3f << 1) | |
| 1403 | +#define LVDS_PD_CH(ch) ((ch) << 1) | |
| 1404 | +#define LVDS_RST (1 << 0) | |
| 1405 | + | |
| 1406 | +#define LVDS_PHY_CTL_EXT 0x2A8 | |
| 1407 | + | |
| 1408 | +/* LVDS_PHY_CTRL_EXT1 */ | |
| 1409 | +#define LVDS_SSC_RNGE_MASK (0x7ff << 16) | |
| 1410 | +#define LVDS_SSC_RNGE_SHIFT (16) | |
| 1411 | +#define LVDS_RESERVE_IN_MASK (0xf << 12) | |
| 1412 | +#define LVDS_RESERVE_IN_SHIFT (12) | |
| 1413 | +#define LVDS_TEST_MON_MASK (0x7 << 8) | |
| 1414 | +#define LVDS_TEST_MON_SHIFT (8) | |
| 1415 | +#define LVDS_POL_SWAP_MASK (0x3f << 0) | |
| 1416 | +#define LVDS_POL_SWAP_SHIFT (0) | |
| 1417 | + | |
| 1418 | +/* LVDS_PHY_CTRL_EXT2 */ | |
| 1419 | +#define LVDS_TX_DIF_AMP_MASK (0xf << 24) | |
| 1420 | +#define LVDS_TX_DIF_AMP_SHIFT (24) | |
| 1421 | +#define LVDS_TX_DIF_CM_MASK (0x3 << 22) | |
| 1422 | +#define LVDS_TX_DIF_CM_SHIFT (22) | |
| 1423 | +#define LVDS_SELLV_TXCLK_MASK (0x1f << 16) | |
| 1424 | +#define LVDS_SELLV_TXCLK_SHIFT (16) | |
| 1425 | +#define LVDS_TX_CMFB_EN (0x1 << 15) | |
| 1426 | +#define LVDS_TX_TERM_EN (0x1 << 14) | |
| 1427 | +#define LVDS_SELLV_TXDATA_MASK (0x1f << 8) | |
| 1428 | +#define LVDS_SELLV_TXDATA_SHIFT (8) | |
| 1429 | +#define LVDS_SELLV_OP7_MASK (0x3 << 6) | |
| 1430 | +#define LVDS_SELLV_OP7_SHIFT (6) | |
| 1431 | +#define LVDS_SELLV_OP6_MASK (0x3 << 4) | |
| 1432 | +#define LVDS_SELLV_OP6_SHIFT (4) | |
| 1433 | +#define LVDS_SELLV_OP9_MASK (0x3 << 2) | |
| 1434 | +#define LVDS_SELLV_OP9_SHIFT (2) | |
| 1435 | +#define LVDS_STRESSTST_EN (0x1 << 0) | |
| 1436 | + | |
| 1437 | +/* LVDS_PHY_CTRL_EXT3 */ | |
| 1438 | +#define LVDS_KVCO_MASK (0xf << 28) | |
| 1439 | +#define LVDS_KVCO_SHIFT (28) | |
| 1440 | +#define LVDS_CTUNE_MASK (0x3 << 26) | |
| 1441 | +#define LVDS_CTUNE_SHIFT (26) | |
| 1442 | +#define LVDS_VREG_IVREF_MASK (0x3 << 24) | |
| 1443 | +#define LVDS_VREG_IVREF_SHIFT (24) | |
| 1444 | +#define LVDS_VDDL_MASK (0xf << 20) | |
| 1445 | +#define LVDS_VDDL_SHIFT (20) | |
| 1446 | +#define LVDS_VDDM_MASK (0x3 << 18) | |
| 1447 | +#define LVDS_VDDM_SHIFT (18) | |
| 1448 | +#define LVDS_FBDIV_MASK (0xf << 8) | |
| 1449 | +#define LVDS_FBDIV_SHIFT (8) | |
| 1450 | +#define LVDS_REFDIV_MASK (0x7f << 0) | |
| 1451 | +#define LVDS_REFDIV_SHIFT (0) | |
| 1452 | + | |
| 1453 | +/* LVDS_PHY_CTRL_EXT4 */ | |
| 1454 | +#define LVDS_SSC_FREQ_DIV_MASK (0xffff << 16) | |
| 1455 | +#define LVDS_SSC_FREQ_DIV_SHIFT (16) | |
| 1456 | +#define LVDS_INTPI_MASK (0xf << 12) | |
| 1457 | +#define LVDS_INTPI_SHIFT (12) | |
| 1458 | +#define LVDS_VCODIV_SEL_SE_MASK (0xf << 8) | |
| 1459 | +#define LVDS_VCODIV_SEL_SE_SHIFT (8) | |
| 1460 | +#define LVDS_RESET_INTP_EXT (0x1 << 7) | |
| 1461 | +#define LVDS_VCO_VRNG_MASK (0x7 << 4) | |
| 1462 | +#define LVDS_VCO_VRNG_SHIFT (4) | |
| 1463 | +#define LVDS_PI_EN (0x1 << 3) | |
| 1464 | +#define LVDS_ICP_MASK (0x7 << 0) | |
| 1465 | +#define LVDS_ICP_SHIFT (0) | |
| 1466 | + | |
| 1467 | +/* LVDS_PHY_CTRL_EXT5 */ | |
| 1468 | +#define LVDS_FREQ_OFFSET_MASK (0x1ffff << 15) | |
| 1469 | +#define LVDS_FREQ_OFFSET_SHIFT (15) | |
| 1470 | +#define LVDS_FREQ_OFFSET_VALID (0x1 << 2) | |
| 1471 | +#define LVDS_FREQ_OFFSET_MODE_CK_DIV4_OUT (0x1 << 1) | |
| 1472 | +#define LVDS_FREQ_OFFSET_MODE_EN (0x1 << 0) | |
| 1473 | + | |
| 1474 | +/* VDMA */ | |
| 1475 | +struct vdma_ch_regs { | |
| 1476 | +#define VDMA_DC_SADDR_1 0x320 | |
| 1477 | +#define VDMA_DC_SADDR_2 0x3A0 | |
| 1478 | +#define VDMA_DC_SZ_1 0x324 | |
| 1479 | +#define VDMA_DC_SZ_2 0x3A4 | |
| 1480 | +#define VDMA_CTRL_1 0x328 | |
| 1481 | +#define VDMA_CTRL_2 0x3A8 | |
| 1482 | +#define VDMA_SRC_SZ_1 0x32C | |
| 1483 | +#define VDMA_SRC_SZ_2 0x3AC | |
| 1484 | +#define VDMA_SA_1 0x330 | |
| 1485 | +#define VDMA_SA_2 0x3B0 | |
| 1486 | +#define VDMA_DA_1 0x334 | |
| 1487 | +#define VDMA_DA_2 0x3B4 | |
| 1488 | +#define VDMA_SZ_1 0x338 | |
| 1489 | +#define VDMA_SZ_2 0x3B8 | |
| 1490 | + u32 dc_saddr; | |
| 1491 | + u32 dc_size; | |
| 1492 | + u32 ctrl; | |
| 1493 | + u32 src_size; | |
| 1494 | + u32 src_addr; | |
| 1495 | + u32 dst_addr; | |
| 1496 | + u32 dst_size; | |
| 1497 | +#define VDMA_PITCH_1 0x33C | |
| 1498 | +#define VDMA_PITCH_2 0x3BC | |
| 1499 | +#define VDMA_ROT_CTRL_1 0x340 | |
| 1500 | +#define VDMA_ROT_CTRL_2 0x3C0 | |
| 1501 | +#define VDMA_RAM_CTRL0_1 0x344 | |
| 1502 | +#define VDMA_RAM_CTRL0_2 0x3C4 | |
| 1503 | +#define VDMA_RAM_CTRL1_1 0x348 | |
| 1504 | +#define VDMA_RAM_CTRL1_2 0x3C8 | |
| 1505 | + u32 pitch; | |
| 1506 | + u32 rot_ctrl; | |
| 1507 | + u32 ram_ctrl0; | |
| 1508 | + u32 ram_ctrl1; | |
| 1509 | + | |
| 1510 | +}; | |
| 1511 | +struct vdma_regs { | |
| 1512 | +#define VDMA_ARBR_CTRL 0x300 | |
| 1513 | +#define VDMA_IRQR 0x304 | |
| 1514 | +#define VDMA_IRQM 0x308 | |
| 1515 | +#define VDMA_IRQS 0x30C | |
| 1516 | +#define VDMA_MDMA_ARBR_CTRL 0x310 | |
| 1517 | + u32 arbr_ctr; | |
| 1518 | + u32 irq_raw; | |
| 1519 | + u32 irq_mask; | |
| 1520 | + u32 irq_status; | |
| 1521 | + u32 mdma_arbr_ctrl; | |
| 1522 | + u32 reserved[3]; | |
| 1523 | + | |
| 1524 | + struct vdma_ch_regs ch1; | |
| 1525 | + u32 reserved2[21]; | |
| 1526 | + struct vdma_ch_regs ch2; | |
| 1527 | +}; | |
| 1528 | + | |
| 1529 | +/* CMU */ | |
| 1530 | +#define CMU_PIP_DE_H_CFG 0x0008 | |
| 1531 | +#define CMU_PRI1_H_CFG 0x000C | |
| 1532 | +#define CMU_PRI2_H_CFG 0x0010 | |
| 1533 | +#define CMU_ACE_MAIN_DE1_H_CFG 0x0014 | |
| 1534 | +#define CMU_ACE_MAIN_DE2_H_CFG 0x0018 | |
| 1535 | +#define CMU_ACE_PIP_DE1_H_CFG 0x001C | |
| 1536 | +#define CMU_ACE_PIP_DE2_H_CFG 0x0020 | |
| 1537 | +#define CMU_PIP_DE_V_CFG 0x0024 | |
| 1538 | +#define CMU_PRI_V_CFG 0x0028 | |
| 1539 | +#define CMU_ACE_MAIN_DE_V_CFG 0x002C | |
| 1540 | +#define CMU_ACE_PIP_DE_V_CFG 0x0030 | |
| 1541 | +#define CMU_BAR_0_CFG 0x0034 | |
| 1542 | +#define CMU_BAR_1_CFG 0x0038 | |
| 1543 | +#define CMU_BAR_2_CFG 0x003C | |
| 1544 | +#define CMU_BAR_3_CFG 0x0040 | |
| 1545 | +#define CMU_BAR_4_CFG 0x0044 | |
| 1546 | +#define CMU_BAR_5_CFG 0x0048 | |
| 1547 | +#define CMU_BAR_6_CFG 0x004C | |
| 1548 | +#define CMU_BAR_7_CFG 0x0050 | |
| 1549 | +#define CMU_BAR_8_CFG 0x0054 | |
| 1550 | +#define CMU_BAR_9_CFG 0x0058 | |
| 1551 | +#define CMU_BAR_10_CFG 0x005C | |
| 1552 | +#define CMU_BAR_11_CFG 0x0060 | |
| 1553 | +#define CMU_BAR_12_CFG 0x0064 | |
| 1554 | +#define CMU_BAR_13_CFG 0x0068 | |
| 1555 | +#define CMU_BAR_14_CFG 0x006C | |
| 1556 | +#define CMU_BAR_15_CFG 0x0070 | |
| 1557 | +#define CMU_BAR_CTRL 0x0074 | |
| 1558 | +#define PATTERN_TOTAL 0x0078 | |
| 1559 | +#define PATTERN_ACTIVE 0x007C | |
| 1560 | +#define PATTERN_FRONT_PORCH 0x0080 | |
| 1561 | +#define PATTERN_BACK_PORCH 0x0084 | |
| 1562 | +#define CMU_CLK_CTRL 0x0088 | |
| 1563 | + | |
| 1564 | +#define CMU_ICSC_M_C0_L 0x0900 | |
| 1565 | +#define CMU_ICSC_M_C0_H 0x0901 | |
| 1566 | +#define CMU_ICSC_M_C1_L 0x0902 | |
| 1567 | +#define CMU_ICSC_M_C1_H 0x0903 | |
| 1568 | +#define CMU_ICSC_M_C2_L 0x0904 | |
| 1569 | +#define CMU_ICSC_M_C2_H 0x0905 | |
| 1570 | +#define CMU_ICSC_M_C3_L 0x0906 | |
| 1571 | +#define CMU_ICSC_M_C3_H 0x0907 | |
| 1572 | +#define CMU_ICSC_M_C4_L 0x0908 | |
| 1573 | +#define CMU_ICSC_M_C4_H 0x0909 | |
| 1574 | +#define CMU_ICSC_M_C5_L 0x090A | |
| 1575 | +#define CMU_ICSC_M_C5_H 0x090B | |
| 1576 | +#define CMU_ICSC_M_C6_L 0x090C | |
| 1577 | +#define CMU_ICSC_M_C6_H 0x090D | |
| 1578 | +#define CMU_ICSC_M_C7_L 0x090E | |
| 1579 | +#define CMU_ICSC_M_C7_H 0x090F | |
| 1580 | +#define CMU_ICSC_M_C8_L 0x0910 | |
| 1581 | +#define CMU_ICSC_M_C8_H 0x0911 | |
| 1582 | +#define CMU_ICSC_M_O1_0 0x0914 | |
| 1583 | +#define CMU_ICSC_M_O1_1 0x0915 | |
| 1584 | +#define CMU_ICSC_M_O1_2 0x0916 | |
| 1585 | +#define CMU_ICSC_M_O2_0 0x0918 | |
| 1586 | +#define CMU_ICSC_M_O2_1 0x0919 | |
| 1587 | +#define CMU_ICSC_M_O2_2 0x091A | |
| 1588 | +#define CMU_ICSC_M_O3_0 0x091C | |
| 1589 | +#define CMU_ICSC_M_O3_1 0x091D | |
| 1590 | +#define CMU_ICSC_M_O3_2 0x091E | |
| 1591 | +#define CMU_ICSC_P_C0_L 0x0920 | |
| 1592 | +#define CMU_ICSC_P_C0_H 0x0921 | |
| 1593 | +#define CMU_ICSC_P_C1_L 0x0922 | |
| 1594 | +#define CMU_ICSC_P_C1_H 0x0923 | |
| 1595 | +#define CMU_ICSC_P_C2_L 0x0924 | |
| 1596 | +#define CMU_ICSC_P_C2_H 0x0925 | |
| 1597 | +#define CMU_ICSC_P_C3_L 0x0926 | |
| 1598 | +#define CMU_ICSC_P_C3_H 0x0927 | |
| 1599 | +#define CMU_ICSC_P_C4_L 0x0928 | |
| 1600 | +#define CMU_ICSC_P_C4_H 0x0929 | |
| 1601 | +#define CMU_ICSC_P_C5_L 0x092A | |
| 1602 | +#define CMU_ICSC_P_C5_H 0x092B | |
| 1603 | +#define CMU_ICSC_P_C6_L 0x092C | |
| 1604 | +#define CMU_ICSC_P_C6_H 0x092D | |
| 1605 | +#define CMU_ICSC_P_C7_L 0x092E | |
| 1606 | +#define CMU_ICSC_P_C7_H 0x092F | |
| 1607 | +#define CMU_ICSC_P_C8_L 0x0930 | |
| 1608 | +#define CMU_ICSC_P_C8_H 0x0931 | |
| 1609 | +#define CMU_ICSC_P_O1_0 0x0934 | |
| 1610 | +#define CMU_ICSC_P_O1_1 0x0935 | |
| 1611 | +#define CMU_ICSC_P_O1_2 0x0936 | |
| 1612 | +#define CMU_ICSC_P_O2_0 0x0938 | |
| 1613 | +#define CMU_ICSC_P_O2_1 0x0939 | |
| 1614 | +#define CMU_ICSC_P_O2_2 0x093A | |
| 1615 | +#define CMU_ICSC_P_O3_0 0x093C | |
| 1616 | +#define CMU_ICSC_P_O3_1 0x093D | |
| 1617 | +#define CMU_ICSC_P_O3_2 0x093E | |
| 1618 | +#define CMU_BR_M_EN 0x0940 | |
| 1619 | +#define CMU_BR_M_TH1_L 0x0942 | |
| 1620 | +#define CMU_BR_M_TH1_H 0x0943 | |
| 1621 | +#define CMU_BR_M_TH2_L 0x0944 | |
| 1622 | +#define CMU_BR_M_TH2_H 0x0945 | |
| 1623 | +#define CMU_ACE_M_EN 0x0950 | |
| 1624 | +#define CMU_ACE_M_WFG1 0x0951 | |
| 1625 | +#define CMU_ACE_M_WFG2 0x0952 | |
| 1626 | +#define CMU_ACE_M_WFG3 0x0953 | |
| 1627 | +#define CMU_ACE_M_TH0 0x0954 | |
| 1628 | +#define CMU_ACE_M_TH1 0x0955 | |
| 1629 | +#define CMU_ACE_M_TH2 0x0956 | |
| 1630 | +#define CMU_ACE_M_TH3 0x0957 | |
| 1631 | +#define CMU_ACE_M_TH4 0x0958 | |
| 1632 | +#define CMU_ACE_M_TH5 0x0959 | |
| 1633 | +#define CMU_ACE_M_OP0_L 0x095A | |
| 1634 | +#define CMU_ACE_M_OP0_H 0x095B | |
| 1635 | +#define CMU_ACE_M_OP5_L 0x095C | |
| 1636 | +#define CMU_ACE_M_OP5_H 0x095D | |
| 1637 | +#define CMU_ACE_M_GB2 0x095E | |
| 1638 | +#define CMU_ACE_M_GB3 0x095F | |
| 1639 | +#define CMU_ACE_M_MS1 0x0960 | |
| 1640 | +#define CMU_ACE_M_MS2 0x0961 | |
| 1641 | +#define CMU_ACE_M_MS3 0x0962 | |
| 1642 | +#define CMU_BR_P_EN 0x0970 | |
| 1643 | +#define CMU_BR_P_TH1_L 0x0972 | |
| 1644 | +#define CMU_BR_P_TH1_H 0x0973 | |
| 1645 | +#define CMU_BR_P_TH2_L 0x0974 | |
| 1646 | +#define CMU_BR_P_TH2_H 0x0975 | |
| 1647 | +#define CMU_ACE_P_EN 0x0980 | |
| 1648 | +#define CMU_ACE_P_WFG1 0x0981 | |
| 1649 | +#define CMU_ACE_P_WFG2 0x0982 | |
| 1650 | +#define CMU_ACE_P_WFG3 0x0983 | |
| 1651 | +#define CMU_ACE_P_TH0 0x0984 | |
| 1652 | +#define CMU_ACE_P_TH1 0x0985 | |
| 1653 | +#define CMU_ACE_P_TH2 0x0986 | |
| 1654 | +#define CMU_ACE_P_TH3 0x0987 | |
| 1655 | +#define CMU_ACE_P_TH4 0x0988 | |
| 1656 | +#define CMU_ACE_P_TH5 0x0989 | |
| 1657 | +#define CMU_ACE_P_OP0_L 0x098A | |
| 1658 | +#define CMU_ACE_P_OP0_H 0x098B | |
| 1659 | +#define CMU_ACE_P_OP5_L 0x098C | |
| 1660 | +#define CMU_ACE_P_OP5_H 0x098D | |
| 1661 | +#define CMU_ACE_P_GB2 0x098E | |
| 1662 | +#define CMU_ACE_P_GB3 0x098F | |
| 1663 | +#define CMU_ACE_P_MS1 0x0990 | |
| 1664 | +#define CMU_ACE_P_MS2 0x0991 | |
| 1665 | +#define CMU_ACE_P_MS3 0x0992 | |
| 1666 | +#define CMU_FTDC_M_EN 0x09A0 | |
| 1667 | +#define CMU_FTDC_P_EN 0x09A1 | |
| 1668 | +#define CMU_FTDC_INLOW_L 0x09A2 | |
| 1669 | +#define CMU_FTDC_INLOW_H 0x09A3 | |
| 1670 | +#define CMU_FTDC_INHIGH_L 0x09A4 | |
| 1671 | +#define CMU_FTDC_INHIGH_H 0x09A5 | |
| 1672 | +#define CMU_FTDC_OUTLOW_L 0x09A6 | |
| 1673 | +#define CMU_FTDC_OUTLOW_H 0x09A7 | |
| 1674 | +#define CMU_FTDC_OUTHIGH_L 0x09A8 | |
| 1675 | +#define CMU_FTDC_OUTHIGH_H 0x09A9 | |
| 1676 | +#define CMU_FTDC_YLOW 0x09AA | |
| 1677 | +#define CMU_FTDC_YHIGH 0x09AB | |
| 1678 | +#define CMU_FTDC_CH1 0x09AC | |
| 1679 | +#define CMU_FTDC_CH2_L 0x09AE | |
| 1680 | +#define CMU_FTDC_CH2_H 0x09AF | |
| 1681 | +#define CMU_FTDC_CH3_L 0x09B0 | |
| 1682 | +#define CMU_FTDC_CH3_H 0x09B1 | |
| 1683 | +#define CMU_FTDC_1_C00_6 0x09B2 | |
| 1684 | +#define CMU_FTDC_1_C01_6 0x09B8 | |
| 1685 | +#define CMU_FTDC_1_C11_6 0x09BE | |
| 1686 | +#define CMU_FTDC_1_C10_6 0x09C4 | |
| 1687 | +#define CMU_FTDC_1_OFF00_6 0x09CA | |
| 1688 | +#define CMU_FTDC_1_OFF10_6 0x09D0 | |
| 1689 | +#define CMU_HS_M_EN 0x0A00 | |
| 1690 | +#define CMU_HS_M_AX1_L 0x0A02 | |
| 1691 | +#define CMU_HS_M_AX1_H 0x0A03 | |
| 1692 | +#define CMU_HS_M_AX2_L 0x0A04 | |
| 1693 | +#define CMU_HS_M_AX2_H 0x0A05 | |
| 1694 | +#define CMU_HS_M_AX3_L 0x0A06 | |
| 1695 | +#define CMU_HS_M_AX3_H 0x0A07 | |
| 1696 | +#define CMU_HS_M_AX4_L 0x0A08 | |
| 1697 | +#define CMU_HS_M_AX4_H 0x0A09 | |
| 1698 | +#define CMU_HS_M_AX5_L 0x0A0A | |
| 1699 | +#define CMU_HS_M_AX5_H 0x0A0B | |
| 1700 | +#define CMU_HS_M_AX6_L 0x0A0C | |
| 1701 | +#define CMU_HS_M_AX6_H 0x0A0D | |
| 1702 | +#define CMU_HS_M_AX7_L 0x0A0E | |
| 1703 | +#define CMU_HS_M_AX7_H 0x0A0F | |
| 1704 | +#define CMU_HS_M_AX8_L 0x0A10 | |
| 1705 | +#define CMU_HS_M_AX8_H 0x0A11 | |
| 1706 | +#define CMU_HS_M_AX9_L 0x0A12 | |
| 1707 | +#define CMU_HS_M_AX9_H 0x0A13 | |
| 1708 | +#define CMU_HS_M_AX10_L 0x0A14 | |
| 1709 | +#define CMU_HS_M_AX10_H 0x0A15 | |
| 1710 | +#define CMU_HS_M_AX11_L 0x0A16 | |
| 1711 | +#define CMU_HS_M_AX11_H 0x0A17 | |
| 1712 | +#define CMU_HS_M_AX12_L 0x0A18 | |
| 1713 | +#define CMU_HS_M_AX12_H 0x0A19 | |
| 1714 | +#define CMU_HS_M_AX13_L 0x0A1A | |
| 1715 | +#define CMU_HS_M_AX13_H 0x0A1B | |
| 1716 | +#define CMU_HS_M_AX14_L 0x0A1C | |
| 1717 | +#define CMU_HS_M_AX14_H 0x0A1D | |
| 1718 | +#define CMU_HS_M_H1_H14 0x0A1E | |
| 1719 | +#define CMU_HS_M_S1_S14 0x0A2C | |
| 1720 | +#define CMU_HS_M_GL 0x0A3A | |
| 1721 | +#define CMU_HS_M_MAXSAT_RGB_Y_L 0x0A3C | |
| 1722 | +#define CMU_HS_M_MAXSAT_RGB_Y_H 0x0A3D | |
| 1723 | +#define CMU_HS_M_MAXSAT_RCR_L 0x0A3E | |
| 1724 | +#define CMU_HS_M_MAXSAT_RCR_H 0x0A3F | |
| 1725 | +#define CMU_HS_M_MAXSAT_RCB_L 0x0A40 | |
| 1726 | +#define CMU_HS_M_MAXSAT_RCB_H 0x0A41 | |
| 1727 | +#define CMU_HS_M_MAXSAT_GCR_L 0x0A42 | |
| 1728 | +#define CMU_HS_M_MAXSAT_GCR_H 0x0A43 | |
| 1729 | +#define CMU_HS_M_MAXSAT_GCB_L 0x0A44 | |
| 1730 | +#define CMU_HS_M_MAXSAT_GCB_H 0x0A45 | |
| 1731 | +#define CMU_HS_M_MAXSAT_BCR_L 0x0A46 | |
| 1732 | +#define CMU_HS_M_MAXSAT_BCR_H 0x0A47 | |
| 1733 | +#define CMU_HS_M_MAXSAT_BCB_L 0x0A48 | |
| 1734 | +#define CMU_HS_M_MAXSAT_BCB_H 0x0A49 | |
| 1735 | +#define CMU_HS_M_ROFF_L 0x0A4A | |
| 1736 | +#define CMU_HS_M_ROFF_H 0x0A4B | |
| 1737 | +#define CMU_HS_M_GOFF_L 0x0A4C | |
| 1738 | +#define CMU_HS_M_GOFF_H 0x0A4D | |
| 1739 | +#define CMU_HS_M_BOFF_L 0x0A4E | |
| 1740 | +#define CMU_HS_M_BOFF_H 0x0A4F | |
| 1741 | +#define CMU_HS_P_EN 0x0A50 | |
| 1742 | +#define CMU_HS_P_AX1_L 0x0A52 | |
| 1743 | +#define CMU_HS_P_AX1_H 0x0A53 | |
| 1744 | +#define CMU_HS_P_AX2_L 0x0A54 | |
| 1745 | +#define CMU_HS_P_AX2_H 0x0A55 | |
| 1746 | +#define CMU_HS_P_AX3_L 0x0A56 | |
| 1747 | +#define CMU_HS_P_AX3_H 0x0A57 | |
| 1748 | +#define CMU_HS_P_AX4_L 0x0A58 | |
| 1749 | +#define CMU_HS_P_AX4_H 0x0A59 | |
| 1750 | +#define CMU_HS_P_AX5_L 0x0A5A | |
| 1751 | +#define CMU_HS_P_AX5_H 0x0A5B | |
| 1752 | +#define CMU_HS_P_AX6_L 0x0A5C | |
| 1753 | +#define CMU_HS_P_AX6_H 0x0A5D | |
| 1754 | +#define CMU_HS_P_AX7_L 0x0A5E | |
| 1755 | +#define CMU_HS_P_AX7_H 0x0A5F | |
| 1756 | +#define CMU_HS_P_AX8_L 0x0A60 | |
| 1757 | +#define CMU_HS_P_AX8_H 0x0A61 | |
| 1758 | +#define CMU_HS_P_AX9_L 0x0A62 | |
| 1759 | +#define CMU_HS_P_AX9_H 0x0A63 | |
| 1760 | +#define CMU_HS_P_AX10_L 0x0A64 | |
| 1761 | +#define CMU_HS_P_AX10_H 0x0A65 | |
| 1762 | +#define CMU_HS_P_AX11_L 0x0A66 | |
| 1763 | +#define CMU_HS_P_AX11_H 0x0A67 | |
| 1764 | +#define CMU_HS_P_AX12_L 0x0A68 | |
| 1765 | +#define CMU_HS_P_AX12_H 0x0A69 | |
| 1766 | +#define CMU_HS_P_AX13_L 0x0A6A | |
| 1767 | +#define CMU_HS_P_AX13_H 0x0A6B | |
| 1768 | +#define CMU_HS_P_AX14_L 0x0A6C | |
| 1769 | +#define CMU_HS_P_AX14_H 0x0A6D | |
| 1770 | +#define CMU_HS_P_H1_H14 0x0A6E | |
| 1771 | +#define CMU_HS_P_S1_S14 0x0A7C | |
| 1772 | +#define CMU_HS_P_GL 0x0A8A | |
| 1773 | +#define CMU_HS_P_MAXSAT_RGB_Y_L 0x0A8C | |
| 1774 | +#define CMU_HS_P_MAXSAT_RGB_Y_H 0x0A8D | |
| 1775 | +#define CMU_HS_P_MAXSAT_RCR_L 0x0A8E | |
| 1776 | +#define CMU_HS_P_MAXSAT_RCR_H 0x0A8F | |
| 1777 | +#define CMU_HS_P_MAXSAT_RCB_L 0x0A90 | |
| 1778 | +#define CMU_HS_P_MAXSAT_RCB_H 0x0A91 | |
| 1779 | +#define CMU_HS_P_MAXSAT_GCR_L 0x0A92 | |
| 1780 | +#define CMU_HS_P_MAXSAT_GCR_H 0x0A93 | |
| 1781 | +#define CMU_HS_P_MAXSAT_GCB_L 0x0A94 | |
| 1782 | +#define CMU_HS_P_MAXSAT_GCB_H 0x0A95 | |
| 1783 | +#define CMU_HS_P_MAXSAT_BCR_L 0x0A96 | |
| 1784 | +#define CMU_HS_P_MAXSAT_BCR_H 0x0A97 | |
| 1785 | +#define CMU_HS_P_MAXSAT_BCB_L 0x0A98 | |
| 1786 | +#define CMU_HS_P_MAXSAT_BCB_H 0x0A99 | |
| 1787 | +#define CMU_HS_P_ROFF_L 0x0A9A | |
| 1788 | +#define CMU_HS_P_ROFF_H 0x0A9B | |
| 1789 | +#define CMU_HS_P_GOFF_L 0x0A9C | |
| 1790 | +#define CMU_HS_P_GOFF_H 0x0A9D | |
| 1791 | +#define CMU_HS_P_BOFF_L 0x0A9E | |
| 1792 | +#define CMU_HS_P_BOFF_H 0x0A9F | |
| 1793 | +#define CMU_GLCSC_M_C0_L 0x0AA0 | |
| 1794 | +#define CMU_GLCSC_M_C0_H 0x0AA1 | |
| 1795 | +#define CMU_GLCSC_M_C1_L 0x0AA2 | |
| 1796 | +#define CMU_GLCSC_M_C1_H 0x0AA3 | |
| 1797 | +#define CMU_GLCSC_M_C2_L 0x0AA4 | |
| 1798 | +#define CMU_GLCSC_M_C2_H 0x0AA5 | |
| 1799 | +#define CMU_GLCSC_M_C3_L 0x0AA6 | |
| 1800 | +#define CMU_GLCSC_M_C3_H 0x0AA7 | |
| 1801 | +#define CMU_GLCSC_M_C4_L 0x0AA8 | |
| 1802 | +#define CMU_GLCSC_M_C4_H 0x0AA9 | |
| 1803 | +#define CMU_GLCSC_M_C5_L 0x0AAA | |
| 1804 | +#define CMU_GLCSC_M_C5_H 0x0AAB | |
| 1805 | +#define CMU_GLCSC_M_C6_L 0x0AAC | |
| 1806 | +#define CMU_GLCSC_M_C6_H 0x0AAD | |
| 1807 | +#define CMU_GLCSC_M_C7_L 0x0AAE | |
| 1808 | +#define CMU_GLCSC_M_C7_H 0x0AAF | |
| 1809 | +#define CMU_GLCSC_M_C8_L 0x0AB0 | |
| 1810 | +#define CMU_GLCSC_M_C8_H 0x0AB1 | |
| 1811 | +#define CMU_GLCSC_M_O1_1 0x0AB4 | |
| 1812 | +#define CMU_GLCSC_M_O1_2 0x0AB5 | |
| 1813 | +#define CMU_GLCSC_M_O1_3 0x0AB6 | |
| 1814 | +#define CMU_GLCSC_M_O2_1 0x0AB8 | |
| 1815 | +#define CMU_GLCSC_M_O2_2 0x0AB9 | |
| 1816 | +#define CMU_GLCSC_M_O2_3 0x0ABA | |
| 1817 | +#define CMU_GLCSC_M_O3_1 0x0ABC | |
| 1818 | +#define CMU_GLCSC_M_O3_2 0x0ABD | |
| 1819 | +#define CMU_GLCSC_M_O3_3 0x0ABE | |
| 1820 | +#define CMU_GLCSC_P_C0_L 0x0AC0 | |
| 1821 | +#define CMU_GLCSC_P_C0_H 0x0AC1 | |
| 1822 | +#define CMU_GLCSC_P_C1_L 0x0AC2 | |
| 1823 | +#define CMU_GLCSC_P_C1_H 0x0AC3 | |
| 1824 | +#define CMU_GLCSC_P_C2_L 0x0AC4 | |
| 1825 | +#define CMU_GLCSC_P_C2_H 0x0AC5 | |
| 1826 | +#define CMU_GLCSC_P_C3_L 0x0AC6 | |
| 1827 | +#define CMU_GLCSC_P_C3_H 0x0AC7 | |
| 1828 | +#define CMU_GLCSC_P_C4_L 0x0AC8 | |
| 1829 | +#define CMU_GLCSC_P_C4_H 0x0AC9 | |
| 1830 | +#define CMU_GLCSC_P_C5_L 0x0ACA | |
| 1831 | +#define CMU_GLCSC_P_C5_H 0x0ACB | |
| 1832 | +#define CMU_GLCSC_P_C6_L 0x0ACC | |
| 1833 | +#define CMU_GLCSC_P_C6_H 0x0ACD | |
| 1834 | +#define CMU_GLCSC_P_C7_L 0x0ACE | |
| 1835 | +#define CMU_GLCSC_P_C7_H 0x0ACF | |
| 1836 | +#define CMU_GLCSC_P_C8_L 0x0AD0 | |
| 1837 | +#define CMU_GLCSC_P_C8_H 0x0AD1 | |
| 1838 | +#define CMU_GLCSC_P_O1_1 0x0AD4 | |
| 1839 | +#define CMU_GLCSC_P_O1_2 0x0AD5 | |
| 1840 | +#define CMU_GLCSC_P_O1_3 0x0AD6 | |
| 1841 | +#define CMU_GLCSC_P_O2_1 0x0AD8 | |
| 1842 | +#define CMU_GLCSC_P_O2_2 0x0AD9 | |
| 1843 | +#define CMU_GLCSC_P_O2_3 0x0ADA | |
| 1844 | +#define CMU_GLCSC_P_O3_1 0x0ADC | |
| 1845 | +#define CMU_GLCSC_P_O3_2 0x0ADD | |
| 1846 | +#define CMU_GLCSC_P_O3_3 0x0ADE | |
| 1847 | +#define CMU_PIXVAL_M_EN 0x0AE0 | |
| 1848 | +#define CMU_PIXVAL_P_EN 0x0AE1 | |
| 1849 | + | |
| 1850 | +#define CMU_CLK_CTRL_TCLK 0x0 | |
| 1851 | +#define CMU_CLK_CTRL_SCLK 0x2 | |
| 1852 | +#define CMU_CLK_CTRL_MSK 0x2 | |
| 1853 | +#define CMU_CLK_CTRL_ENABLE 0x1 | |
| 1854 | + | |
| 1855 | +#define LCD_TOP_CTRL_TV 0x2 | |
| 1856 | +#define LCD_TOP_CTRL_PN 0x0 | |
| 1857 | +#define LCD_TOP_CTRL_SEL_MSK 0x2 | |
| 1858 | +#define LCD_IO_CMU_IN_SEL_MSK (0x3 << 20) | |
| 1859 | +#define LCD_IO_CMU_IN_SEL_TV 0 | |
| 1860 | +#define LCD_IO_CMU_IN_SEL_PN 1 | |
| 1861 | +#define LCD_IO_CMU_IN_SEL_PN2 2 | |
| 1862 | +#define LCD_IO_TV_OUT_SEL_MSK (0x3 << 26) | |
| 1863 | +#define LCD_IO_PN_OUT_SEL_MSK (0x3 << 24) | |
| 1864 | +#define LCD_IO_PN2_OUT_SEL_MSK (0x3 << 28) | |
| 1865 | +#define LCD_IO_TV_OUT_SEL_NON 3 | |
| 1866 | +#define LCD_IO_PN_OUT_SEL_NON 3 | |
| 1867 | +#define LCD_IO_PN2_OUT_SEL_NON 3 | |
| 1868 | +#define LCD_TOP_CTRL_CMU_ENABLE 0x1 | |
| 1869 | +#define LCD_IO_OVERL_MSK 0xC00000 | |
| 1870 | +#define LCD_IO_OVERL_TV 0x0 | |
| 1871 | +#define LCD_IO_OVERL_LCD1 0x400000 | |
| 1872 | +#define LCD_IO_OVERL_LCD2 0xC00000 | |
| 1873 | +#define HINVERT_MSK 0x4 | |
| 1874 | +#define VINVERT_MSK 0x8 | |
| 1875 | +#define HINVERT_LEN 0x2 | |
| 1876 | +#define VINVERT_LEN 0x3 | |
| 1877 | + | |
| 1878 | +#define CMU_CTRL 0x88 | |
| 1879 | +#define CMU_CTRL_A0_MSK 0x6 | |
| 1880 | +#define CMU_CTRL_A0_TV 0x0 | |
| 1881 | +#define CMU_CTRL_A0_LCD1 0x1 | |
| 1882 | +#define CMU_CTRL_A0_LCD2 0x2 | |
| 1883 | +#define CMU_CTRL_A0_HDMI 0x3 | |
| 1884 | + | |
| 1885 | +#define ICR_DRV_ROUTE_OFF 0x0 | |
| 1886 | +#define ICR_DRV_ROUTE_TV 0x1 | |
| 1887 | +#define ICR_DRV_ROUTE_LCD1 0x2 | |
| 1888 | +#define ICR_DRV_ROUTE_LCD2 0x3 | |
| 1889 | + | |
| 1890 | +enum { | |
| 1891 | + PATH_PN = 0, | |
| 1892 | + PATH_TV, | |
| 1893 | + PATH_P2, | |
| 1894 | +}; | |
| 1895 | + | |
| 1896 | +/* | |
| 1897 | + * mmp path describes part of mmp path related info: | |
| 1898 | + * which is hiden in display driver and not exported to buffer driver | |
| 1899 | + */ | |
| 1900 | +struct mmphw_ctrl; | |
| 1901 | +struct mmphw_path_plat { | |
| 1902 | + int id; | |
| 1903 | + struct mmphw_ctrl *ctrl; | |
| 1904 | + struct mmp_path *path; | |
| 1905 | + u32 path_config; | |
| 1906 | + u32 link_config; | |
| 1907 | +}; | |
| 1908 | + | |
| 1909 | +/* mmp ctrl describes mmp controller related info */ | |
| 1910 | +struct mmphw_ctrl { | |
| 1911 | + /* platform related, get from config */ | |
| 1912 | + const char *name; | |
| 1913 | + int irq; | |
| 1914 | + void *reg_base; | |
| 1915 | + struct clk *clk; | |
| 1916 | + | |
| 1917 | + /* sys info */ | |
| 1918 | + struct device *dev; | |
| 1919 | + | |
| 1920 | + /* state */ | |
| 1921 | + int open_count; | |
| 1922 | + int status; | |
| 1923 | + struct mutex access_ok; | |
| 1924 | + | |
| 1925 | + /*pathes*/ | |
| 1926 | + int path_num; | |
| 1927 | + struct mmphw_path_plat path_plats[0]; | |
| 1928 | +}; | |
| 1929 | + | |
| 1930 | +static inline int overlay_is_vid(struct mmp_overlay *overlay) | |
| 1931 | +{ | |
| 1932 | + return overlay->dmafetch_id & 1; | |
| 1933 | +} | |
| 1934 | + | |
| 1935 | +static inline struct mmphw_path_plat *path_to_path_plat(struct mmp_path *path) | |
| 1936 | +{ | |
| 1937 | + return (struct mmphw_path_plat *)path->plat_data; | |
| 1938 | +} | |
| 1939 | + | |
| 1940 | +static inline struct mmphw_ctrl *path_to_ctrl(struct mmp_path *path) | |
| 1941 | +{ | |
| 1942 | + return path_to_path_plat(path)->ctrl; | |
| 1943 | +} | |
| 1944 | + | |
| 1945 | +static inline struct mmphw_ctrl *overlay_to_ctrl(struct mmp_overlay *overlay) | |
| 1946 | +{ | |
| 1947 | + return path_to_ctrl(overlay->path); | |
| 1948 | +} | |
| 1949 | + | |
| 1950 | +static inline void *ctrl_regs(struct mmp_path *path) | |
| 1951 | +{ | |
| 1952 | + return path_to_ctrl(path)->reg_base; | |
| 1953 | +} | |
| 1954 | + | |
| 1955 | +/* path regs, for regs symmetrical for both pathes */ | |
| 1956 | +static inline struct lcd_regs *path_regs(struct mmp_path *path) | |
| 1957 | +{ | |
| 1958 | + if (path->id == PATH_PN) | |
| 1959 | + return (struct lcd_regs *)(ctrl_regs(path) + 0xc0); | |
| 1960 | + else if (path->id == PATH_TV) | |
| 1961 | + return (struct lcd_regs *)ctrl_regs(path); | |
| 1962 | + else if (path->id == PATH_P2) | |
| 1963 | + return (struct lcd_regs *)(ctrl_regs(path) + 0x200); | |
| 1964 | + else { | |
| 1965 | + dev_err(path->dev, "path id %d invalid\n", path->id); | |
| 1966 | + BUG_ON(1); | |
| 1967 | + return NULL; | |
| 1968 | + } | |
| 1969 | +} | |
| 1970 | + | |
| 1971 | +#ifdef CONFIG_MMP_DISP_SPI | |
| 1972 | +extern int lcd_spi_register(struct mmphw_ctrl *ctrl); | |
| 1973 | +#endif | |
| 1974 | +#endif /* _MMP_CTRL_H_ */ | |
| @@ -0,0 +1,180 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/hw/mmp_spi.c | |
| 3 | + * using the spi in LCD controler for commands send | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Guoqing Li <ligq@marvell.com> | |
| 7 | + * Lisa Du <cldu@marvell.com> | |
| 8 | + * Zhou Zhu <zzhu3@marvell.com> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify it | |
| 11 | + * under the terms of the GNU General Public License as published by the | |
| 12 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 13 | + * option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 16 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 17 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 18 | + * more details. | |
| 19 | + * | |
| 20 | + * You should have received a copy of the GNU General Public License along with | |
| 21 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | + * | |
| 23 | + */ | |
| 24 | +#include <linux/errno.h> | |
| 25 | +#include <linux/delay.h> | |
| 26 | +#include <linux/err.h> | |
| 27 | +#include <linux/io.h> | |
| 28 | +#include <linux/spi/spi.h> | |
| 29 | +#include "mmp_ctrl.h" | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * spi_write - write command to the SPI port | |
| 33 | + * @data: can be 8/16/32-bit, MSB justified data to write. | |
| 34 | + * @len: data length. | |
| 35 | + * | |
| 36 | + * Wait bus transfer complete IRQ. | |
| 37 | + * The caller is expected to perform the necessary locking. | |
| 38 | + * | |
| 39 | + * Returns: | |
| 40 | + * %-ETIMEDOUT timeout occurred | |
| 41 | + * 0 success | |
| 42 | + */ | |
| 43 | +static inline int lcd_spi_write(struct spi_device *spi, u32 data) | |
| 44 | +{ | |
| 45 | + int timeout = 100000, isr, ret = 0; | |
| 46 | + u32 tmp; | |
| 47 | + void *reg_base = | |
| 48 | + *(void **)spi_master_get_devdata(spi->master); | |
| 49 | + | |
| 50 | + /* clear ISR */ | |
| 51 | + writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); | |
| 52 | + | |
| 53 | + switch (spi->bits_per_word) { | |
| 54 | + case 8: | |
| 55 | + writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA); | |
| 56 | + break; | |
| 57 | + case 16: | |
| 58 | + writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA); | |
| 59 | + break; | |
| 60 | + case 32: | |
| 61 | + writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA); | |
| 62 | + break; | |
| 63 | + default: | |
| 64 | + dev_err(&spi->dev, "Wrong spi bit length\n"); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /* SPI start to send command */ | |
| 68 | + tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); | |
| 69 | + tmp &= ~CFG_SPI_START_MASK; | |
| 70 | + tmp |= CFG_SPI_START(1); | |
| 71 | + writel(tmp, reg_base + LCD_SPU_SPI_CTRL); | |
| 72 | + | |
| 73 | + isr = readl_relaxed(reg_base + SPU_IRQ_ISR); | |
| 74 | + while (!(isr & SPI_IRQ_ENA_MASK)) { | |
| 75 | + udelay(100); | |
| 76 | + isr = readl_relaxed(reg_base + SPU_IRQ_ISR); | |
| 77 | + if (!--timeout) { | |
| 78 | + ret = -ETIMEDOUT; | |
| 79 | + dev_err(&spi->dev, "spi cmd send time out\n"); | |
| 80 | + break; | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | + tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); | |
| 85 | + tmp &= ~CFG_SPI_START_MASK; | |
| 86 | + tmp |= CFG_SPI_START(0); | |
| 87 | + writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL); | |
| 88 | + | |
| 89 | + writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); | |
| 90 | + | |
| 91 | + return ret; | |
| 92 | +} | |
| 93 | + | |
| 94 | +static int lcd_spi_setup(struct spi_device *spi) | |
| 95 | +{ | |
| 96 | + void *reg_base = | |
| 97 | + *(void **)spi_master_get_devdata(spi->master); | |
| 98 | + u32 tmp; | |
| 99 | + | |
| 100 | + tmp = CFG_SCLKCNT(16) | | |
| 101 | + CFG_TXBITS(spi->bits_per_word) | | |
| 102 | + CFG_SPI_SEL(1) | CFG_SPI_ENA(1) | | |
| 103 | + CFG_SPI_3W4WB(1); | |
| 104 | + writel(tmp, reg_base + LCD_SPU_SPI_CTRL); | |
| 105 | + | |
| 106 | + /* | |
| 107 | + * After set mode it need a time to pull up the spi singals, | |
| 108 | + * or it would cause the wrong waveform when send spi command, | |
| 109 | + * especially on pxa910h | |
| 110 | + */ | |
| 111 | + tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL); | |
| 112 | + if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI) | |
| 113 | + writel_relaxed(IOPAD_DUMB18SPI | | |
| 114 | + (tmp & ~CFG_IOPADMODE_MASK), | |
| 115 | + reg_base + SPU_IOPAD_CONTROL); | |
| 116 | + udelay(20); | |
| 117 | + return 0; | |
| 118 | +} | |
| 119 | + | |
| 120 | +static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m) | |
| 121 | +{ | |
| 122 | + struct spi_transfer *t; | |
| 123 | + int i; | |
| 124 | + | |
| 125 | + list_for_each_entry(t, &m->transfers, transfer_list) { | |
| 126 | + switch (spi->bits_per_word) { | |
| 127 | + case 8: | |
| 128 | + for (i = 0; i < t->len; i++) | |
| 129 | + lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]); | |
| 130 | + break; | |
| 131 | + case 16: | |
| 132 | + for (i = 0; i < t->len/2; i++) | |
| 133 | + lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]); | |
| 134 | + break; | |
| 135 | + case 32: | |
| 136 | + for (i = 0; i < t->len/4; i++) | |
| 137 | + lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]); | |
| 138 | + break; | |
| 139 | + default: | |
| 140 | + dev_err(&spi->dev, "Wrong spi bit length\n"); | |
| 141 | + } | |
| 142 | + } | |
| 143 | + | |
| 144 | + m->status = 0; | |
| 145 | + if (m->complete) | |
| 146 | + m->complete(m->context); | |
| 147 | + return 0; | |
| 148 | +} | |
| 149 | + | |
| 150 | +int lcd_spi_register(struct mmphw_ctrl *ctrl) | |
| 151 | +{ | |
| 152 | + struct spi_master *master; | |
| 153 | + void **p_regbase; | |
| 154 | + int err; | |
| 155 | + | |
| 156 | + master = spi_alloc_master(ctrl->dev, sizeof(void *)); | |
| 157 | + if (!master) { | |
| 158 | + dev_err(ctrl->dev, "unable to allocate SPI master\n"); | |
| 159 | + return -ENOMEM; | |
| 160 | + } | |
| 161 | + p_regbase = spi_master_get_devdata(master); | |
| 162 | + *p_regbase = ctrl->reg_base; | |
| 163 | + | |
| 164 | + /* set bus num to 5 to avoid conflict with other spi hosts */ | |
| 165 | + master->bus_num = 5; | |
| 166 | + master->num_chipselect = 1; | |
| 167 | + master->setup = lcd_spi_setup; | |
| 168 | + master->transfer = lcd_spi_one_transfer; | |
| 169 | + | |
| 170 | + err = spi_register_master(master); | |
| 171 | + if (err < 0) { | |
| 172 | + dev_err(ctrl->dev, "unable to register SPI master\n"); | |
| 173 | + spi_master_put(master); | |
| 174 | + return err; | |
| 175 | + } | |
| 176 | + | |
| 177 | + dev_info(&master->dev, "registered\n"); | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +config MMP_PANEL_TPOHVGA | |
| 2 | + bool "tpohvga panel TJ032MD01BW support" | |
| 3 | + depends on SPI_MASTER | |
| 4 | + default n | |
| 5 | + help | |
| 6 | + tpohvga panel support | |
| @@ -0,0 +1 @@ | ||
| 1 | +obj-$(CONFIG_MMP_PANEL_TPOHVGA) += tpo_tj032md01bw.o | |
| @@ -0,0 +1,186 @@ | ||
| 1 | +/* | |
| 2 | + * linux/drivers/video/mmp/panel/tpo_tj032md01bw.c | |
| 3 | + * active panel using spi interface to do init | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Guoqing Li <ligq@marvell.com> | |
| 7 | + * Lisa Du <cldu@marvell.com> | |
| 8 | + * Zhou Zhu <zzhu3@marvell.com> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify it | |
| 11 | + * under the terms of the GNU General Public License as published by the | |
| 12 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 13 | + * option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 16 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 17 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 18 | + * more details. | |
| 19 | + * | |
| 20 | + * You should have received a copy of the GNU General Public License along with | |
| 21 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | + * | |
| 23 | + */ | |
| 24 | + | |
| 25 | +#include <linux/module.h> | |
| 26 | +#include <linux/moduleparam.h> | |
| 27 | +#include <linux/kernel.h> | |
| 28 | +#include <linux/errno.h> | |
| 29 | +#include <linux/string.h> | |
| 30 | +#include <linux/delay.h> | |
| 31 | +#include <linux/platform_device.h> | |
| 32 | +#include <linux/err.h> | |
| 33 | +#include <linux/spi/spi.h> | |
| 34 | +#include <video/mmp_disp.h> | |
| 35 | + | |
| 36 | +static u16 init[] = { | |
| 37 | + 0x0801, | |
| 38 | + 0x0800, | |
| 39 | + 0x0200, | |
| 40 | + 0x0304, | |
| 41 | + 0x040e, | |
| 42 | + 0x0903, | |
| 43 | + 0x0b18, | |
| 44 | + 0x0c53, | |
| 45 | + 0x0d01, | |
| 46 | + 0x0ee0, | |
| 47 | + 0x0f01, | |
| 48 | + 0x1058, | |
| 49 | + 0x201e, | |
| 50 | + 0x210a, | |
| 51 | + 0x220a, | |
| 52 | + 0x231e, | |
| 53 | + 0x2400, | |
| 54 | + 0x2532, | |
| 55 | + 0x2600, | |
| 56 | + 0x27ac, | |
| 57 | + 0x2904, | |
| 58 | + 0x2aa2, | |
| 59 | + 0x2b45, | |
| 60 | + 0x2c45, | |
| 61 | + 0x2d15, | |
| 62 | + 0x2e5a, | |
| 63 | + 0x2fff, | |
| 64 | + 0x306b, | |
| 65 | + 0x310d, | |
| 66 | + 0x3248, | |
| 67 | + 0x3382, | |
| 68 | + 0x34bd, | |
| 69 | + 0x35e7, | |
| 70 | + 0x3618, | |
| 71 | + 0x3794, | |
| 72 | + 0x3801, | |
| 73 | + 0x395d, | |
| 74 | + 0x3aae, | |
| 75 | + 0x3bff, | |
| 76 | + 0x07c9, | |
| 77 | +}; | |
| 78 | + | |
| 79 | +static u16 poweroff[] = { | |
| 80 | + 0x07d9, | |
| 81 | +}; | |
| 82 | + | |
| 83 | +struct tpohvga_plat_data { | |
| 84 | + void (*plat_onoff)(int status); | |
| 85 | + struct spi_device *spi; | |
| 86 | +}; | |
| 87 | + | |
| 88 | +static void tpohvga_onoff(struct mmp_panel *panel, int status) | |
| 89 | +{ | |
| 90 | + struct tpohvga_plat_data *plat = panel->plat_data; | |
| 91 | + int ret; | |
| 92 | + | |
| 93 | + if (status) { | |
| 94 | + plat->plat_onoff(1); | |
| 95 | + | |
| 96 | + ret = spi_write(plat->spi, init, sizeof(init)); | |
| 97 | + if (ret < 0) | |
| 98 | + dev_warn(panel->dev, "init cmd failed(%d)\n", ret); | |
| 99 | + } else { | |
| 100 | + ret = spi_write(plat->spi, poweroff, sizeof(poweroff)); | |
| 101 | + if (ret < 0) | |
| 102 | + dev_warn(panel->dev, "poweroff cmd failed(%d)\n", ret); | |
| 103 | + | |
| 104 | + plat->plat_onoff(0); | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | |
| 108 | +static struct mmp_mode mmp_modes_tpohvga[] = { | |
| 109 | + [0] = { | |
| 110 | + .pixclock_freq = 10394400, | |
| 111 | + .refresh = 60, | |
| 112 | + .xres = 320, | |
| 113 | + .yres = 480, | |
| 114 | + .hsync_len = 10, | |
| 115 | + .left_margin = 15, | |
| 116 | + .right_margin = 10, | |
| 117 | + .vsync_len = 2, | |
| 118 | + .upper_margin = 4, | |
| 119 | + .lower_margin = 2, | |
| 120 | + .invert_pixclock = 1, | |
| 121 | + .pix_fmt_out = PIXFMT_RGB565, | |
| 122 | + }, | |
| 123 | +}; | |
| 124 | + | |
| 125 | +static int tpohvga_get_modelist(struct mmp_panel *panel, | |
| 126 | + struct mmp_mode **modelist) | |
| 127 | +{ | |
| 128 | + *modelist = mmp_modes_tpohvga; | |
| 129 | + return 1; | |
| 130 | +} | |
| 131 | + | |
| 132 | +static struct mmp_panel panel_tpohvga = { | |
| 133 | + .name = "tpohvga", | |
| 134 | + .panel_type = PANELTYPE_ACTIVE, | |
| 135 | + .get_modelist = tpohvga_get_modelist, | |
| 136 | + .set_onoff = tpohvga_onoff, | |
| 137 | +}; | |
| 138 | + | |
| 139 | +static int tpohvga_probe(struct spi_device *spi) | |
| 140 | +{ | |
| 141 | + struct mmp_mach_panel_info *mi; | |
| 142 | + int ret; | |
| 143 | + struct tpohvga_plat_data *plat_data; | |
| 144 | + | |
| 145 | + /* get configs from platform data */ | |
| 146 | + mi = spi->dev.platform_data; | |
| 147 | + if (mi == NULL) { | |
| 148 | + dev_err(&spi->dev, "%s: no platform data defined\n", __func__); | |
| 149 | + return -EINVAL; | |
| 150 | + } | |
| 151 | + | |
| 152 | + /* setup spi related info */ | |
| 153 | + spi->bits_per_word = 16; | |
| 154 | + ret = spi_setup(spi); | |
| 155 | + if (ret < 0) { | |
| 156 | + dev_err(&spi->dev, "spi setup failed %d", ret); | |
| 157 | + return ret; | |
| 158 | + } | |
| 159 | + | |
| 160 | + plat_data = kzalloc(sizeof(*plat_data), GFP_KERNEL); | |
| 161 | + if (plat_data == NULL) | |
| 162 | + return -ENOMEM; | |
| 163 | + | |
| 164 | + plat_data->spi = spi; | |
| 165 | + plat_data->plat_onoff = mi->plat_set_onoff; | |
| 166 | + panel_tpohvga.plat_data = plat_data; | |
| 167 | + panel_tpohvga.plat_path_name = mi->plat_path_name; | |
| 168 | + panel_tpohvga.dev = &spi->dev; | |
| 169 | + | |
| 170 | + mmp_register_panel(&panel_tpohvga); | |
| 171 | + | |
| 172 | + return 0; | |
| 173 | +} | |
| 174 | + | |
| 175 | +static struct spi_driver panel_tpohvga_driver = { | |
| 176 | + .driver = { | |
| 177 | + .name = "tpo-hvga", | |
| 178 | + .owner = THIS_MODULE, | |
| 179 | + }, | |
| 180 | + .probe = tpohvga_probe, | |
| 181 | +}; | |
| 182 | +module_spi_driver(panel_tpohvga_driver); | |
| 183 | + | |
| 184 | +MODULE_AUTHOR("Lisa Du<cldu@marvell.com>"); | |
| 185 | +MODULE_DESCRIPTION("Panel driver for tpohvga"); | |
| 186 | +MODULE_LICENSE("GPL"); | |
| @@ -1306,7 +1306,7 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi) · 1305 unmodified lines | ||
| 1306 | 1306 | dma_free_writecombine(fbi->device, fbi->fix.smem_len, |
| 1307 | 1307 | fbi->screen_base, fbi->fix.smem_start); |
| 1308 | 1308 | |
| 1309 | − fbi->screen_base = 0; | |
| 1309 | + fbi->screen_base = NULL; | |
| 1310 | 1310 | mutex_lock(&fbi->mm_lock); |
| 1311 | 1311 | fbi->fix.smem_start = 0; |
| 1312 | 1312 | fbi->fix.smem_len = 0; |
| @@ -616,6 +616,7 @@ v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) · 615 unmodified lines | ||
| 616 | 616 | lock_page(page); |
| 617 | 617 | if (page->mapping != inode->i_mapping) |
| 618 | 618 | goto out_unlock; |
| 619 | + wait_for_stable_page(page); | |
| 619 | 620 | |
| 620 | 621 | return VM_FAULT_LOCKED; |
| 621 | 622 | out_unlock: |
| @@ -1249,7 +1249,7 @@ static int writenote(struct memelfnote *men, struct file *file, · 1248 unmodified lines | ||
| 1249 | 1249 | #undef DUMP_WRITE |
| 1250 | 1250 | |
| 1251 | 1251 | static void fill_elf_header(struct elfhdr *elf, int segs, |
| 1252 | − u16 machine, u32 flags, u8 osabi) | |
| 1252 | + u16 machine, u32 flags) | |
| 1253 | 1253 | { |
| 1254 | 1254 | memset(elf, 0, sizeof(*elf)); |
| 1255 | 1255 | |
| @@ -1634,7 +1634,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, · 378 unmodified lines | ||
| 1634 | 1634 | * Initialize the ELF file header. |
| 1635 | 1635 | */ |
| 1636 | 1636 | fill_elf_header(elf, phdrs, |
| 1637 | − view->e_machine, view->e_flags, view->ei_osabi); | |
| 1637 | + view->e_machine, view->e_flags); | |
| 1638 | 1638 | |
| 1639 | 1639 | /* |
| 1640 | 1640 | * Allocate a structure for each thread. |
| @@ -1874,7 +1874,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, · 233 unmodified lines | ||
| 1874 | 1874 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
| 1875 | 1875 | |
| 1876 | 1876 | /* Set up header */ |
| 1877 | − fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI); | |
| 1877 | + fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); | |
| 1878 | 1878 | |
| 1879 | 1879 | /* |
| 1880 | 1880 | * Set up the notes in similar form to SVR4 core dumps made |
| @@ -994,6 +994,7 @@ int revalidate_disk(struct gendisk *disk) · 993 unmodified lines | ||
| 994 | 994 | |
| 995 | 995 | mutex_lock(&bdev->bd_mutex); |
| 996 | 996 | check_disk_size_change(disk, bdev); |
| 997 | + bdev->bd_invalidated = 0; | |
| 997 | 998 | mutex_unlock(&bdev->bd_mutex); |
| 998 | 999 | bdput(bdev); |
| 999 | 1000 | return ret; |
| @@ -2359,7 +2359,7 @@ int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, · 2358 unmodified lines | ||
| 2359 | 2359 | if (unlikely(ret < 0)) |
| 2360 | 2360 | goto out_unlock; |
| 2361 | 2361 | set_page_dirty(page); |
| 2362 | − wait_on_page_writeback(page); | |
| 2362 | + wait_for_stable_page(page); | |
| 2363 | 2363 | return 0; |
| 2364 | 2364 | out_unlock: |
| 2365 | 2365 | unlock_page(page); |
| @@ -1037,10 +1037,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level) · 1036 unmodified lines | ||
| 1037 | 1037 | static int configfs_depend_prep(struct dentry *origin, |
| 1038 | 1038 | struct config_item *target) |
| 1039 | 1039 | { |
| 1040 | − struct configfs_dirent *child_sd, *sd = origin->d_fsdata; | |
| 1040 | + struct configfs_dirent *child_sd, *sd; | |
| 1041 | 1041 | int ret = 0; |
| 1042 | 1042 | |
| 1043 | − BUG_ON(!origin || !sd); | |
| 1043 | + BUG_ON(!origin || !origin->d_fsdata); | |
| 1044 | + sd = origin->d_fsdata; | |
| 1044 | 1045 | |
| 1045 | 1046 | if (sd->s_element == target) /* Boo-yah */ |
| 1046 | 1047 | goto out; |
| @@ -2065,6 +2065,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) · 2064 unmodified lines | ||
| 2065 | 2065 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": |
| 2066 | 2066 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": |
| 2067 | 2067 | "writeback"); |
| 2068 | + sb->s_flags |= MS_SNAP_STABLE; | |
| 2068 | 2069 | |
| 2069 | 2070 | return 0; |
| 2070 | 2071 | |
| @@ -4968,7 +4968,7 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) · 4967 unmodified lines | ||
| 4968 | 4968 | 0, len, NULL, |
| 4969 | 4969 | ext4_bh_unmapped)) { |
| 4970 | 4970 | /* Wait so that we don't change page under IO */ |
| 4971 | − wait_on_page_writeback(page); | |
| 4971 | + wait_for_stable_page(page); | |
| 4972 | 4972 | ret = VM_FAULT_LOCKED; |
| 4973 | 4973 | goto out; |
| 4974 | 4974 | } |
| @@ -483,7 +483,7 @@ out: · 482 unmodified lines | ||
| 483 | 483 | gfs2_holder_uninit(&gh); |
| 484 | 484 | if (ret == 0) { |
| 485 | 485 | set_page_dirty(page); |
| 486 | − wait_on_page_writeback(page); | |
| 486 | + wait_for_stable_page(page); | |
| 487 | 487 | } |
| 488 | 488 | sb_end_pagefault(inode->i_sb); |
| 489 | 489 | return block_page_mkwrite_return(ret); |
| @@ -126,7 +126,7 @@ static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) · 125 unmodified lines | ||
| 126 | 126 | nilfs_transaction_commit(inode->i_sb); |
| 127 | 127 | |
| 128 | 128 | mapped: |
| 129 | − wait_on_page_writeback(page); | |
| 129 | + wait_for_stable_page(page); | |
| 130 | 130 | out: |
| 131 | 131 | sb_end_pagefault(inode->i_sb); |
| 132 | 132 | return block_page_mkwrite_return(ret); |
| @@ -576,8 +576,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, · 575 unmodified lines | ||
| 576 | 576 | |
| 577 | 577 | /* don't allow invalid bits: we don't want flags set */ |
| 578 | 578 | mask = inotify_arg_to_mask(arg); |
| 579 | − if (unlikely(!(mask & IN_ALL_EVENTS))) | |
| 580 | − return -EINVAL; | |
| 581 | 579 | |
| 582 | 580 | fsn_mark = fsnotify_find_inode_mark(group, inode); |
| 583 | 581 | if (!fsn_mark) |
| @@ -629,8 +627,6 @@ static int inotify_new_watch(struct fsnotify_group *group, · 45 unmodified lines | ||
| 629 | 627 | |
| 630 | 628 | /* don't allow invalid bits: we don't want flags set */ |
| 631 | 629 | mask = inotify_arg_to_mask(arg); |
| 632 | − if (unlikely(!(mask & IN_ALL_EVENTS))) | |
| 633 | − return -EINVAL; | |
| 634 | 630 | |
| 635 | 631 | tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); |
| 636 | 632 | if (unlikely(!tmp_i_mark)) |
| @@ -6751,8 +6751,7 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, · 6750 unmodified lines | ||
| 6751 | 6751 | mlog_errno(ret); |
| 6752 | 6752 | |
| 6753 | 6753 | out: |
| 6754 | − if (pages) | |
| 6755 | − kfree(pages); | |
| 6754 | + kfree(pages); | |
| 6756 | 6755 | |
| 6757 | 6756 | return ret; |
| 6758 | 6757 | } |
| @@ -1194,6 +1194,7 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping, · 1193 unmodified lines | ||
| 1194 | 1194 | goto out; |
| 1195 | 1195 | } |
| 1196 | 1196 | } |
| 1197 | + wait_for_stable_page(wc->w_pages[i]); | |
| 1197 | 1198 | |
| 1198 | 1199 | if (index == target_index) |
| 1199 | 1200 | wc->w_target_page = wc->w_pages[i]; |
| @@ -1471,8 +1471,7 @@ static void o2hb_region_release(struct config_item *item) · 1470 unmodified lines | ||
| 1471 | 1471 | |
| 1472 | 1472 | mlog(ML_HEARTBEAT, "hb region release (%s)\n", reg->hr_dev_name); |
| 1473 | 1473 | |
| 1474 | − if (reg->hr_tmp_block) | |
| 1475 | − kfree(reg->hr_tmp_block); | |
| 1474 | + kfree(reg->hr_tmp_block); | |
| 1476 | 1475 | |
| 1477 | 1476 | if (reg->hr_slot_data) { |
| 1478 | 1477 | for (i = 0; i < reg->hr_num_pages; i++) { |
| @@ -1486,8 +1485,7 @@ static void o2hb_region_release(struct config_item *item) · 7 unmodified lines | ||
| 1486 | 1485 | if (reg->hr_bdev) |
| 1487 | 1486 | blkdev_put(reg->hr_bdev, FMODE_READ|FMODE_WRITE); |
| 1488 | 1487 | |
| 1489 | − if (reg->hr_slots) | |
| 1490 | − kfree(reg->hr_slots); | |
| 1488 | + kfree(reg->hr_slots); | |
| 1491 | 1489 | |
| 1492 | 1490 | kfree(reg->hr_db_regnum); |
| 1493 | 1491 | kfree(reg->hr_db_livenodes); |
| @@ -1165,10 +1165,8 @@ out: · 1164 unmodified lines | ||
| 1165 | 1165 | o2net_debug_del_nst(&nst); /* must be before dropping sc and node */ |
| 1166 | 1166 | if (sc) |
| 1167 | 1167 | sc_put(sc); |
| 1168 | − if (vec) | |
| 1169 | − kfree(vec); | |
| 1170 | − if (msg) | |
| 1171 | − kfree(msg); | |
| 1168 | + kfree(vec); | |
| 1169 | + kfree(msg); | |
| 1172 | 1170 | o2net_complete_nsw(nn, &nsw, 0, 0, 0); |
| 1173 | 1171 | return ret; |
| 1174 | 1172 | } |
| @@ -319,9 +319,7 @@ static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm) · 318 unmodified lines | ||
| 319 | 319 | if (dlm->master_hash) |
| 320 | 320 | dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); |
| 321 | 321 | |
| 322 | − if (dlm->name) | |
| 323 | − kfree(dlm->name); | |
| 324 | − | |
| 322 | + kfree(dlm->name); | |
| 325 | 323 | kfree(dlm); |
| 326 | 324 | } |
| 327 | 325 | |
| @@ -2545,6 +2545,7 @@ int ocfs2_super_lock(struct ocfs2_super *osb, · 2544 unmodified lines | ||
| 2545 | 2545 | * everything is up to the caller :) */ |
| 2546 | 2546 | status = ocfs2_should_refresh_lock_res(lockres); |
| 2547 | 2547 | if (status < 0) { |
| 2548 | + ocfs2_cluster_unlock(osb, lockres, level); | |
| 2548 | 2549 | mlog_errno(status); |
| 2549 | 2550 | goto bail; |
| 2550 | 2551 | } |
| @@ -2553,8 +2554,10 @@ int ocfs2_super_lock(struct ocfs2_super *osb, · 2 unmodified lines | ||
| 2553 | 2554 | |
| 2554 | 2555 | ocfs2_complete_lock_res_refresh(lockres, status); |
| 2555 | 2556 | |
| 2556 | − if (status < 0) | |
| 2557 | + if (status < 0) { | |
| 2558 | + ocfs2_cluster_unlock(osb, lockres, level); | |
| 2557 | 2559 | mlog_errno(status); |
| 2560 | + } | |
| 2558 | 2561 | ocfs2_track_lock_refresh(lockres); |
| 2559 | 2562 | } |
| 2560 | 2563 | bail: |
| @@ -282,8 +282,7 @@ search: · 281 unmodified lines | ||
| 282 | 282 | spin_unlock(&oi->ip_lock); |
| 283 | 283 | |
| 284 | 284 | out: |
| 285 | − if (new_emi) | |
| 286 | − kfree(new_emi); | |
| 285 | + kfree(new_emi); | |
| 287 | 286 | } |
| 288 | 287 | |
| 289 | 288 | static int ocfs2_last_eb_is_empty(struct inode *inode, |
| @@ -1234,11 +1234,8 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, · 1233 unmodified lines | ||
| 1234 | 1234 | /* Though we wish to avoid it, we are in fact safe in |
| 1235 | 1235 | * skipping local alloc cleanup as fsck.ocfs2 is more |
| 1236 | 1236 | * than capable of reclaiming unused space. */ |
| 1237 | − if (la_dinode) | |
| 1238 | − kfree(la_dinode); | |
| 1239 | − | |
| 1240 | − if (tl_dinode) | |
| 1241 | − kfree(tl_dinode); | |
| 1237 | + kfree(la_dinode); | |
| 1238 | + kfree(tl_dinode); | |
| 1242 | 1239 | |
| 1243 | 1240 | if (qrec) |
| 1244 | 1241 | ocfs2_free_quota_recovery(qrec); |
| @@ -1408,8 +1405,7 @@ bail: · 163 unmodified lines | ||
| 1408 | 1405 | |
| 1409 | 1406 | mutex_unlock(&osb->recovery_lock); |
| 1410 | 1407 | |
| 1411 | − if (rm_quota) | |
| 1412 | − kfree(rm_quota); | |
| 1408 | + kfree(rm_quota); | |
| 1413 | 1409 | |
| 1414 | 1410 | /* no one is callint kthread_stop() for us so the kthread() api |
| 1415 | 1411 | * requires that we call do_exit(). And it isn't exported, but |
| @@ -476,8 +476,7 @@ out: · 475 unmodified lines | ||
| 476 | 476 | if (local_alloc_inode) |
| 477 | 477 | iput(local_alloc_inode); |
| 478 | 478 | |
| 479 | − if (alloc_copy) | |
| 480 | − kfree(alloc_copy); | |
| 479 | + kfree(alloc_copy); | |
| 481 | 480 | } |
| 482 | 481 | |
| 483 | 482 | /* |
| @@ -534,7 +533,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb, · 50 unmodified lines | ||
| 534 | 533 | mlog_errno(status); |
| 535 | 534 | |
| 536 | 535 | bail: |
| 537 | − if ((status < 0) && (*alloc_copy)) { | |
| 536 | + if (status < 0) { | |
| 538 | 537 | kfree(*alloc_copy); |
| 539 | 538 | *alloc_copy = NULL; |
| 540 | 539 | } |
| @@ -1290,8 +1289,7 @@ bail: · 749 unmodified lines | ||
| 1290 | 1289 | if (main_bm_inode) |
| 1291 | 1290 | iput(main_bm_inode); |
| 1292 | 1291 | |
| 1293 | − if (alloc_copy) | |
| 1294 | − kfree(alloc_copy); | |
| 1292 | + kfree(alloc_copy); | |
| 1295 | 1293 | |
| 1296 | 1294 | if (ac) |
| 1297 | 1295 | ocfs2_free_alloc_context(ac); |
| @@ -376,7 +376,7 @@ static int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn) · 375 unmodified lines | ||
| 376 | 376 | dlm_register_eviction_cb(dlm, &priv->op_eviction_cb); |
| 377 | 377 | |
| 378 | 378 | out_free: |
| 379 | − if (rc && conn->cc_private) | |
| 379 | + if (rc) | |
| 380 | 380 | kfree(conn->cc_private); |
| 381 | 381 | |
| 382 | 382 | out: |
| @@ -2525,8 +2525,7 @@ static int ocfs2_check_volume(struct ocfs2_super *osb) · 2524 unmodified lines | ||
| 2525 | 2525 | mlog_errno(status); |
| 2526 | 2526 | |
| 2527 | 2527 | finally: |
| 2528 | − if (local_alloc) | |
| 2529 | − kfree(local_alloc); | |
| 2528 | + kfree(local_alloc); | |
| 2530 | 2529 | |
| 2531 | 2530 | if (status) |
| 2532 | 2531 | mlog_errno(status); |
| @@ -2553,8 +2552,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) · 20 unmodified lines | ||
| 2553 | 2552 | * we free it here. |
| 2554 | 2553 | */ |
| 2555 | 2554 | kfree(osb->journal); |
| 2556 | − if (osb->local_alloc_copy) | |
| 2557 | − kfree(osb->local_alloc_copy); | |
| 2555 | + kfree(osb->local_alloc_copy); | |
| 2558 | 2556 | kfree(osb->uuid_str); |
| 2559 | 2557 | ocfs2_put_dlm_debug(osb->osb_dlm_debug); |
| 2560 | 2558 | memset(osb, 0, sizeof(struct ocfs2_super)); |
| @@ -91,8 +91,7 @@ static struct inode **get_local_system_inode(struct ocfs2_super *osb, · 90 unmodified lines | ||
| 91 | 91 | } else |
| 92 | 92 | osb->local_system_inodes = local_system_inodes; |
| 93 | 93 | spin_unlock(&osb->osb_lock); |
| 94 | − if (unlikely(free)) | |
| 95 | − kfree(free); | |
| 94 | + kfree(free); | |
| 96 | 95 | } |
| 97 | 96 | |
| 98 | 97 | index = (slot * NUM_LOCAL_SYSTEM_INODES) + |
| @@ -1522,6 +1522,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, · 1521 unmodified lines | ||
| 1522 | 1522 | ubifs_release_dirty_inode_budget(c, ui); |
| 1523 | 1523 | } |
| 1524 | 1524 | |
| 1525 | + wait_for_stable_page(page); | |
| 1525 | 1526 | unlock_page(page); |
| 1526 | 1527 | return 0; |
| 1527 | 1528 | |
| @@ -254,6 +254,7 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio); · 253 unmodified lines | ||
| 254 | 254 | #define BDI_CAP_EXEC_MAP 0x00000040 |
| 255 | 255 | #define BDI_CAP_NO_ACCT_WB 0x00000080 |
| 256 | 256 | #define BDI_CAP_SWAP_BACKED 0x00000100 |
| 257 | +#define BDI_CAP_STABLE_WRITES 0x00000200 | |
| 257 | 258 | |
| 258 | 259 | #define BDI_CAP_VMFLAGS \ |
| 259 | 260 | (BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP) |
| @@ -308,6 +309,11 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout); · 48 unmodified lines | ||
| 308 | 309 | int pdflush_proc_obsolete(struct ctl_table *table, int write, |
| 309 | 310 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 310 | 311 | |
| 312 | +static inline bool bdi_cap_stable_pages_required(struct backing_dev_info *bdi) | |
| 313 | +{ | |
| 314 | + return bdi->capabilities & BDI_CAP_STABLE_WRITES; | |
| 315 | +} | |
| 316 | + | |
| 311 | 317 | static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi) |
| 312 | 318 | { |
| 313 | 319 | return !(bdi->capabilities & BDI_CAP_NO_WRITEBACK); |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | #define _LINUX_BUG_H |
| 3 | 3 | |
| 4 | 4 | #include <asm/bug.h> |
| 5 | +#include <linux/compiler.h> | |
| 5 | 6 | |
| 6 | 7 | enum bug_trap_type { |
| 7 | 8 | BUG_TRAP_TYPE_NONE = 0, |
| @@ -12,11 +13,12 @@ enum bug_trap_type { · 4 unmodified lines | ||
| 12 | 13 | struct pt_regs; |
| 13 | 14 | |
| 14 | 15 | #ifdef __CHECKER__ |
| 15 | −#define BUILD_BUG_ON_NOT_POWER_OF_2(n) | |
| 16 | +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) | |
| 16 | 17 | #define BUILD_BUG_ON_ZERO(e) (0) |
| 17 | 18 | #define BUILD_BUG_ON_NULL(e) ((void*)0) |
| 18 | 19 | #define BUILD_BUG_ON_INVALID(e) (0) |
| 19 | −#define BUILD_BUG_ON(condition) | |
| 20 | +#define BUILD_BUG_ON_MSG(cond, msg) (0) | |
| 21 | +#define BUILD_BUG_ON(condition) (0) | |
| 20 | 22 | #define BUILD_BUG() (0) |
| 21 | 23 | #else /* __CHECKER__ */ |
| 22 | 24 | |
| @@ -38,30 +40,38 @@ struct pt_regs; · 15 unmodified lines | ||
| 38 | 40 | */ |
| 39 | 41 | #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e)))) |
| 40 | 42 | |
| 43 | +/** | |
| 44 | + * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied | |
| 45 | + * error message. | |
| 46 | + * @condition: the condition which the compiler should know is false. | |
| 47 | + * | |
| 48 | + * See BUILD_BUG_ON for description. | |
| 49 | + */ | |
| 50 | +#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) | |
| 51 | + | |
| 41 | 52 | /** |
| 42 | 53 | * BUILD_BUG_ON - break compile if a condition is true. |
| 43 | 54 | * @condition: the condition which the compiler should know is false. |
| 44 | 55 | * |
| 45 | 56 | * If you have some code which relies on certain constants being equal, or |
| 46 | − * other compile-time-evaluated condition, you should use BUILD_BUG_ON to | |
| 57 | + * some other compile-time-evaluated condition, you should use BUILD_BUG_ON to | |
| 47 | 58 | * detect if someone changes it. |
| 48 | 59 | * |
| 49 | − * The implementation uses gcc's reluctance to create a negative array, but | |
| 50 | − * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments | |
| 51 | − * to inline functions). So as a fallback we use the optimizer; if it can't | |
| 52 | − * prove the condition is false, it will cause a link error on the undefined | |
| 53 | − * "__build_bug_on_failed". This error message can be harder to track down | |
| 54 | − * though, hence the two different methods. | |
| 60 | + * The implementation uses gcc's reluctance to create a negative array, but gcc | |
| 61 | + * (as of 4.4) only emits that error for obvious cases (e.g. not arguments to | |
| 62 | + * inline functions). Luckily, in 4.3 they added the "error" function | |
| 63 | + * attribute just for this type of case. Thus, we use a negative sized array | |
| 64 | + * (should always create an error on gcc versions older than 4.4) and then call | |
| 65 | + * an undefined function with the error attribute (should always create an | |
| 66 | + * error on gcc 4.3 and later). If for some reason, neither creates a | |
| 67 | + * compile-time error, we'll still have a link-time error, which is harder to | |
| 68 | + * track down. | |
| 55 | 69 | */ |
| 56 | 70 | #ifndef __OPTIMIZE__ |
| 57 | 71 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) |
| 58 | 72 | #else |
| 59 | −extern int __build_bug_on_failed; | |
| 60 | −#define BUILD_BUG_ON(condition) \ | |
| 61 | − do { \ | |
| 62 | − ((void)sizeof(char[1 - 2*!!(condition)])); \ | |
| 63 | − if (condition) __build_bug_on_failed = 1; \ | |
| 64 | − } while(0) | |
| 73 | +#define BUILD_BUG_ON(condition) \ | |
| 74 | + BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) | |
| 65 | 75 | #endif |
| 66 | 76 | |
| 67 | 77 | /** |
| @@ -71,12 +81,7 @@ extern int __build_bug_on_failed; · 3 unmodified lines | ||
| 71 | 81 | * build time, you should use BUILD_BUG to detect if it is |
| 72 | 82 | * unexpectedly used. |
| 73 | 83 | */ |
| 74 | −#define BUILD_BUG() \ | |
| 75 | − do { \ | |
| 76 | − extern void __build_bug_failed(void) \ | |
| 77 | − __linktime_error("BUILD_BUG failed"); \ | |
| 78 | − __build_bug_failed(); \ | |
| 79 | − } while (0) | |
| 84 | +#define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") | |
| 80 | 85 | |
| 81 | 86 | #endif /* __CHECKER__ */ |
| 82 | 87 | |
| @@ -5,6 +5,9 @@ · 4 unmodified lines | ||
| 5 | 5 | /* |
| 6 | 6 | * Common definitions for all gcc versions go here. |
| 7 | 7 | */ |
| 8 | +#define GCC_VERSION (__GNUC__ * 10000 \ | |
| 9 | + + __GNUC_MINOR__ * 100 \ | |
| 10 | + + __GNUC_PATCHLEVEL__) | |
| 8 | 11 | |
| 9 | 12 | |
| 10 | 13 | /* Optimization barrier */ |
| @@ -2,22 +2,22 @@ · 1 unmodified line | ||
| 2 | 2 | #error "Please don't include <linux/compiler-gcc3.h> directly, include <linux/compiler.h> instead." |
| 3 | 3 | #endif |
| 4 | 4 | |
| 5 | −#if __GNUC_MINOR__ < 2 | |
| 5 | +#if GCC_VERSION < 30200 | |
| 6 | 6 | # error Sorry, your compiler is too old - please upgrade it. |
| 7 | 7 | #endif |
| 8 | 8 | |
| 9 | −#if __GNUC_MINOR__ >= 3 | |
| 9 | +#if GCC_VERSION >= 30300 | |
| 10 | 10 | # define __used __attribute__((__used__)) |
| 11 | 11 | #else |
| 12 | 12 | # define __used __attribute__((__unused__)) |
| 13 | 13 | #endif |
| 14 | 14 | |
| 15 | −#if __GNUC_MINOR__ >= 4 | |
| 15 | +#if GCC_VERSION >= 30400 | |
| 16 | 16 | #define __must_check __attribute__((warn_unused_result)) |
| 17 | 17 | #endif |
| 18 | 18 | |
| 19 | 19 | #ifdef CONFIG_GCOV_KERNEL |
| 20 | −# if __GNUC_MINOR__ < 4 | |
| 20 | +# if GCC_VERSION < 30400 | |
| 21 | 21 | # error "GCOV profiling support for gcc versions below 3.4 not included" |
| 22 | 22 | # endif /* __GNUC_MINOR__ */ |
| 23 | 23 | #endif /* CONFIG_GCOV_KERNEL */ |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | /* GCC 4.1.[01] miscompiles __weak */ |
| 6 | 6 | #ifdef __KERNEL__ |
| 7 | −# if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1 | |
| 7 | +# if GCC_VERSION >= 40100 && GCC_VERSION <= 40101 | |
| 8 | 8 | # error Your version of gcc miscompiles the __weak directive |
| 9 | 9 | # endif |
| 10 | 10 | #endif |
| @@ -13,7 +13,11 @@ · 2 unmodified lines | ||
| 13 | 13 | #define __must_check __attribute__((warn_unused_result)) |
| 14 | 14 | #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) |
| 15 | 15 | |
| 16 | −#if __GNUC_MINOR__ >= 3 | |
| 16 | +#if GCC_VERSION >= 40100 | |
| 17 | +# define __compiletime_object_size(obj) __builtin_object_size(obj, 0) | |
| 18 | +#endif | |
| 19 | + | |
| 20 | +#if GCC_VERSION >= 40300 | |
| 17 | 21 | /* Mark functions as cold. gcc will assume any path leading to a call |
| 18 | 22 | to them will be unlikely. This means a lot of manual unlikely()s |
| 19 | 23 | are unnecessary now for any paths leading to the usual suspects |
| @@ -29,11 +33,15 @@ · 9 unmodified lines | ||
| 29 | 33 | the kernel context */ |
| 30 | 34 | #define __cold __attribute__((__cold__)) |
| 31 | 35 | |
| 32 | −#define __linktime_error(message) __attribute__((__error__(message))) | |
| 33 | − | |
| 34 | 36 | #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) |
| 35 | 37 | |
| 36 | −#if __GNUC_MINOR__ >= 5 | |
| 38 | +#ifndef __CHECKER__ | |
| 39 | +# define __compiletime_warning(message) __attribute__((warning(message))) | |
| 40 | +# define __compiletime_error(message) __attribute__((error(message))) | |
| 41 | +#endif /* __CHECKER__ */ | |
| 42 | +#endif /* GCC_VERSION >= 40300 */ | |
| 43 | + | |
| 44 | +#if GCC_VERSION >= 40500 | |
| 37 | 45 | /* |
| 38 | 46 | * Mark a position in code as unreachable. This can be used to |
| 39 | 47 | * suppress control flow warnings after asm blocks that transfer |
| @@ -48,30 +56,22 @@ · 8 unmodified lines | ||
| 48 | 56 | /* Mark a function definition as prohibited from being cloned. */ |
| 49 | 57 | #define __noclone __attribute__((__noclone__)) |
| 50 | 58 | |
| 51 | −#endif | |
| 52 | −#endif | |
| 59 | +#endif /* GCC_VERSION >= 40500 */ | |
| 53 | 60 | |
| 54 | −#if __GNUC_MINOR__ >= 6 | |
| 61 | +#if GCC_VERSION >= 40600 | |
| 55 | 62 | /* |
| 56 | 63 | * Tell the optimizer that something else uses this function or variable. |
| 57 | 64 | */ |
| 58 | 65 | #define __visible __attribute__((externally_visible)) |
| 59 | 66 | #endif |
| 60 | 67 | |
| 61 | −#if __GNUC_MINOR__ > 0 | |
| 62 | −#define __compiletime_object_size(obj) __builtin_object_size(obj, 0) | |
| 63 | −#endif | |
| 64 | −#if __GNUC_MINOR__ >= 3 && !defined(__CHECKER__) | |
| 65 | −#define __compiletime_warning(message) __attribute__((warning(message))) | |
| 66 | −#define __compiletime_error(message) __attribute__((error(message))) | |
| 67 | −#endif | |
| 68 | 68 | |
| 69 | 69 | #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP |
| 70 | −#if __GNUC_MINOR__ >= 4 | |
| 70 | +#if GCC_VERSION >= 40400 | |
| 71 | 71 | #define __HAVE_BUILTIN_BSWAP32__ |
| 72 | 72 | #define __HAVE_BUILTIN_BSWAP64__ |
| 73 | 73 | #endif |
| 74 | −#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6) | |
| 74 | +#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600) | |
| 75 | 75 | #define __HAVE_BUILTIN_BSWAP16__ |
| 76 | 76 | #endif |
| 77 | −#endif | |
| 77 | +#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ | |
| @@ -307,10 +307,36 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); · 306 unmodified lines | ||
| 307 | 307 | #endif |
| 308 | 308 | #ifndef __compiletime_error |
| 309 | 309 | # define __compiletime_error(message) |
| 310 | +# define __compiletime_error_fallback(condition) \ | |
| 311 | + do { ((void)sizeof(char[1 - 2 * condition])); } while (0) | |
| 312 | +#else | |
| 313 | +# define __compiletime_error_fallback(condition) do { } while (0) | |
| 310 | 314 | #endif |
| 311 | −#ifndef __linktime_error | |
| 312 | −# define __linktime_error(message) | |
| 313 | −#endif | |
| 315 | + | |
| 316 | +#define __compiletime_assert(condition, msg, prefix, suffix) \ | |
| 317 | + do { \ | |
| 318 | + bool __cond = !(condition); \ | |
| 319 | + extern void prefix ## suffix(void) __compiletime_error(msg); \ | |
| 320 | + if (__cond) \ | |
| 321 | + prefix ## suffix(); \ | |
| 322 | + __compiletime_error_fallback(__cond); \ | |
| 323 | + } while (0) | |
| 324 | + | |
| 325 | +#define _compiletime_assert(condition, msg, prefix, suffix) \ | |
| 326 | + __compiletime_assert(condition, msg, prefix, suffix) | |
| 327 | + | |
| 328 | +/** | |
| 329 | + * compiletime_assert - break build and emit msg if condition is false | |
| 330 | + * @condition: a compile-time constant condition to check | |
| 331 | + * @msg: a message to emit if condition is false | |
| 332 | + * | |
| 333 | + * In tradition of POSIX assert, this macro will break the build if the | |
| 334 | + * supplied condition is *false*, emitting the supplied error message if the | |
| 335 | + * compiler has support to do so. | |
| 336 | + */ | |
| 337 | +#define compiletime_assert(condition, msg) \ | |
| 338 | + _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) | |
| 339 | + | |
| 314 | 340 | /* |
| 315 | 341 | * Prevent the compiler from merging or refetching accesses. The compiler |
| 316 | 342 | * is also forbidden from reordering successive instances of ACCESS_ONCE(), |
| @@ -359,7 +359,9 @@ extern void lockdep_trace_alloc(gfp_t mask); · 358 unmodified lines | ||
| 359 | 359 | |
| 360 | 360 | #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) |
| 361 | 361 | |
| 362 | −#define lockdep_assert_held(l) WARN_ON(debug_locks && !lockdep_is_held(l)) | |
| 362 | +#define lockdep_assert_held(l) do { \ | |
| 363 | + WARN_ON(debug_locks && !lockdep_is_held(l)); \ | |
| 364 | + } while (0) | |
| 363 | 365 | |
| 364 | 366 | #define lockdep_recursing(tsk) ((tsk)->lockdep_recursion) |
| 365 | 367 | |
| @@ -414,6 +414,7 @@ static inline void wait_on_page_writeback(struct page *page) · 413 unmodified lines | ||
| 414 | 414 | } |
| 415 | 415 | |
| 416 | 416 | extern void end_page_writeback(struct page *page); |
| 417 | +void wait_for_stable_page(struct page *page); | |
| 417 | 418 | |
| 418 | 419 | /* |
| 419 | 420 | * Add an arbitrary waiter to a page's wait queue |
| @@ -49,12 +49,24 @@ · 48 unmodified lines | ||
| 49 | 49 | #define LP8556_FAST_CONFIG BIT(7) /* use it if EPROMs should be maintained |
| 50 | 50 | when exiting the low power mode */ |
| 51 | 51 | |
| 52 | +/* CONFIG register - LP8557 */ | |
| 53 | +#define LP8557_PWM_STANDBY BIT(7) | |
| 54 | +#define LP8557_PWM_FILTER BIT(6) | |
| 55 | +#define LP8557_RELOAD_EPROM BIT(3) /* use it if EPROMs should be reset | |
| 56 | + when the backlight turns on */ | |
| 57 | +#define LP8557_OFF_OPENLEDS BIT(2) | |
| 58 | +#define LP8557_PWM_CONFIG LP8557_PWM_ONLY | |
| 59 | +#define LP8557_I2C_CONFIG LP8557_I2C_ONLY | |
| 60 | +#define LP8557_COMB1_CONFIG LP8557_COMBINED1 | |
| 61 | +#define LP8557_COMB2_CONFIG LP8557_COMBINED2 | |
| 62 | + | |
| 52 | 63 | enum lp855x_chip_id { |
| 53 | 64 | LP8550, |
| 54 | 65 | LP8551, |
| 55 | 66 | LP8552, |
| 56 | 67 | LP8553, |
| 57 | 68 | LP8556, |
| 69 | + LP8557, | |
| 58 | 70 | }; |
| 59 | 71 | |
| 60 | 72 | enum lp855x_brightness_ctrl_mode { |
| @@ -89,6 +101,13 @@ enum lp8556_brightness_source { · 28 unmodified lines | ||
| 89 | 101 | LP8556_COMBINED2, /* pwm + i2c after the shaper block */ |
| 90 | 102 | }; |
| 91 | 103 | |
| 104 | +enum lp8557_brightness_source { | |
| 105 | + LP8557_PWM_ONLY, | |
| 106 | + LP8557_I2C_ONLY, | |
| 107 | + LP8557_COMBINED1, /* pwm + i2c after the shaper block */ | |
| 108 | + LP8557_COMBINED2, /* pwm + i2c before the shaper block */ | |
| 109 | +}; | |
| 110 | + | |
| 92 | 111 | struct lp855x_rom_data { |
| 93 | 112 | u8 addr; |
| 94 | 113 | u8 val; |
| @@ -252,6 +252,15 @@ extern void dump_stack(void) __cold; · 251 unmodified lines | ||
| 252 | 252 | printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) |
| 253 | 253 | #define pr_cont_once(fmt, ...) \ |
| 254 | 254 | printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__) |
| 255 | + | |
| 256 | +#if defined(DEBUG) | |
| 257 | +#define pr_devel_once(fmt, ...) \ | |
| 258 | + printk_once(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) | |
| 259 | +#else | |
| 260 | +#define pr_devel_once(fmt, ...) \ | |
| 261 | + no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) | |
| 262 | +#endif | |
| 263 | + | |
| 255 | 264 | /* If you are writing a driver, please use dev_dbg instead */ |
| 256 | 265 | #if defined(DEBUG) |
| 257 | 266 | #define pr_debug_once(fmt, ...) \ |
| @@ -295,6 +304,15 @@ extern void dump_stack(void) __cold; · 37 unmodified lines | ||
| 295 | 304 | #define pr_info_ratelimited(fmt, ...) \ |
| 296 | 305 | printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) |
| 297 | 306 | /* no pr_cont_ratelimited, don't do that... */ |
| 307 | + | |
| 308 | +#if defined(DEBUG) | |
| 309 | +#define pr_devel_ratelimited(fmt, ...) \ | |
| 310 | + printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) | |
| 311 | +#else | |
| 312 | +#define pr_devel_ratelimited(fmt, ...) \ | |
| 313 | + no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) | |
| 314 | +#endif | |
| 315 | + | |
| 298 | 316 | /* If you are writing a driver, please use dev_dbg instead */ |
| 299 | 317 | #if defined(DEBUG) |
| 300 | 318 | #define pr_debug_ratelimited(fmt, ...) \ |
| @@ -89,7 +89,8 @@ void kick_all_cpus_sync(void); · 88 unmodified lines | ||
| 89 | 89 | #ifdef CONFIG_USE_GENERIC_SMP_HELPERS |
| 90 | 90 | void __init call_function_init(void); |
| 91 | 91 | void generic_smp_call_function_single_interrupt(void); |
| 92 | −void generic_smp_call_function_interrupt(void); | |
| 92 | +#define generic_smp_call_function_interrupt \ | |
| 93 | + generic_smp_call_function_single_interrupt | |
| 93 | 94 | #else |
| 94 | 95 | static inline void call_function_init(void) { } |
| 95 | 96 | #endif |
| @@ -49,14 +49,14 @@ typedef __s64 Elf64_Sxword; · 48 unmodified lines | ||
| 49 | 49 | * |
| 50 | 50 | * Specifications are available in: |
| 51 | 51 | * |
| 52 | − * - Sun microsystems: Linker and Libraries. | |
| 53 | − * Part No: 817-1984-17, September 2008. | |
| 54 | − * URL: http://docs.sun.com/app/docs/doc/817-1984 | |
| 52 | + * - Oracle: Linker and Libraries. | |
| 53 | + * Part No: 817–1984–19, August 2011. | |
| 54 | + * http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf | |
| 55 | 55 | * |
| 56 | 56 | * - System V ABI AMD64 Architecture Processor Supplement |
| 57 | − * Draft Version 0.99., | |
| 58 | − * May 11, 2009. | |
| 59 | − * URL: http://www.x86-64.org/ | |
| 57 | + * Draft Version 0.99.4, | |
| 58 | + * January 13, 2010. | |
| 59 | + * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf | |
| 60 | 60 | */ |
| 61 | 61 | #define PN_XNUM 0xffff |
| 62 | 62 | |
| @@ -86,6 +86,9 @@ struct inodes_stat_t { · 85 unmodified lines | ||
| 86 | 86 | #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ |
| 87 | 87 | #define MS_I_VERSION (1<<23) /* Update inode I_version field */ |
| 88 | 88 | #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ |
| 89 | + | |
| 90 | +/* These sb flags are internal to the kernel */ | |
| 91 | +#define MS_SNAP_STABLE (1<<27) /* Snapshot pages during writeback, if needed */ | |
| 89 | 92 | #define MS_NOSEC (1<<28) |
| 90 | 93 | #define MS_BORN (1<<29) |
| 91 | 94 | #define MS_ACTIVE (1<<30) |
| @@ -220,7 +220,6 @@ struct mipi_dsim_config { · 219 unmodified lines | ||
| 220 | 220 | struct mipi_dsim_device { |
| 221 | 221 | struct device *dev; |
| 222 | 222 | int id; |
| 223 | − struct resource *res; | |
| 224 | 223 | struct clk *clock; |
| 225 | 224 | unsigned int irq; |
| 226 | 225 | void __iomem *reg_base; |
| @@ -0,0 +1,352 @@ | ||
| 1 | +/* | |
| 2 | + * linux/include/video/mmp_disp.h | |
| 3 | + * Header file for Marvell MMP Display Controller | |
| 4 | + * | |
| 5 | + * Copyright (C) 2012 Marvell Technology Group Ltd. | |
| 6 | + * Authors: Zhou Zhu <zzhu3@marvell.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify it | |
| 9 | + * under the terms of the GNU General Public License as published by the | |
| 10 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 11 | + * option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 14 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 16 | + * more details. | |
| 17 | + * | |
| 18 | + * You should have received a copy of the GNU General Public License along with | |
| 19 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 20 | + * | |
| 21 | + */ | |
| 22 | + | |
| 23 | +#ifndef _MMP_DISP_H_ | |
| 24 | +#define _MMP_DISP_H_ | |
| 25 | +#include <linux/kthread.h> | |
| 26 | + | |
| 27 | +enum { | |
| 28 | + PIXFMT_UYVY = 0, | |
| 29 | + PIXFMT_VYUY, | |
| 30 | + PIXFMT_YUYV, | |
| 31 | + PIXFMT_YUV422P, | |
| 32 | + PIXFMT_YVU422P, | |
| 33 | + PIXFMT_YUV420P, | |
| 34 | + PIXFMT_YVU420P, | |
| 35 | + PIXFMT_RGB565 = 0x100, | |
| 36 | + PIXFMT_BGR565, | |
| 37 | + PIXFMT_RGB1555, | |
| 38 | + PIXFMT_BGR1555, | |
| 39 | + PIXFMT_RGB888PACK, | |
| 40 | + PIXFMT_BGR888PACK, | |
| 41 | + PIXFMT_RGB888UNPACK, | |
| 42 | + PIXFMT_BGR888UNPACK, | |
| 43 | + PIXFMT_RGBA888, | |
| 44 | + PIXFMT_BGRA888, | |
| 45 | + PIXFMT_RGB666, /* for output usage */ | |
| 46 | + PIXFMT_PSEUDOCOLOR = 0x200, | |
| 47 | +}; | |
| 48 | + | |
| 49 | +static inline int pixfmt_to_stride(int pix_fmt) | |
| 50 | +{ | |
| 51 | + switch (pix_fmt) { | |
| 52 | + case PIXFMT_RGB565: | |
| 53 | + case PIXFMT_BGR565: | |
| 54 | + case PIXFMT_RGB1555: | |
| 55 | + case PIXFMT_BGR1555: | |
| 56 | + case PIXFMT_UYVY: | |
| 57 | + case PIXFMT_VYUY: | |
| 58 | + case PIXFMT_YUYV: | |
| 59 | + return 2; | |
| 60 | + case PIXFMT_RGB888UNPACK: | |
| 61 | + case PIXFMT_BGR888UNPACK: | |
| 62 | + case PIXFMT_RGBA888: | |
| 63 | + case PIXFMT_BGRA888: | |
| 64 | + return 4; | |
| 65 | + case PIXFMT_RGB888PACK: | |
| 66 | + case PIXFMT_BGR888PACK: | |
| 67 | + return 3; | |
| 68 | + case PIXFMT_YUV422P: | |
| 69 | + case PIXFMT_YVU422P: | |
| 70 | + case PIXFMT_YUV420P: | |
| 71 | + case PIXFMT_YVU420P: | |
| 72 | + case PIXFMT_PSEUDOCOLOR: | |
| 73 | + return 1; | |
| 74 | + default: | |
| 75 | + return 0; | |
| 76 | + } | |
| 77 | +} | |
| 78 | + | |
| 79 | +/* parameters used by path/overlay */ | |
| 80 | +/* overlay related para: win/addr */ | |
| 81 | +struct mmp_win { | |
| 82 | + /* position/size of window */ | |
| 83 | + u16 xsrc; | |
| 84 | + u16 ysrc; | |
| 85 | + u16 xdst; | |
| 86 | + u16 ydst; | |
| 87 | + u16 xpos; | |
| 88 | + u16 ypos; | |
| 89 | + u16 left_crop; | |
| 90 | + u16 right_crop; | |
| 91 | + u16 up_crop; | |
| 92 | + u16 bottom_crop; | |
| 93 | + int pix_fmt; | |
| 94 | +}; | |
| 95 | + | |
| 96 | +struct mmp_addr { | |
| 97 | + /* phys address */ | |
| 98 | + u32 phys[6]; | |
| 99 | +}; | |
| 100 | + | |
| 101 | +/* path related para: mode */ | |
| 102 | +struct mmp_mode { | |
| 103 | + const char *name; | |
| 104 | + u32 refresh; | |
| 105 | + u32 xres; | |
| 106 | + u32 yres; | |
| 107 | + u32 left_margin; | |
| 108 | + u32 right_margin; | |
| 109 | + u32 upper_margin; | |
| 110 | + u32 lower_margin; | |
| 111 | + u32 hsync_len; | |
| 112 | + u32 vsync_len; | |
| 113 | + u32 hsync_invert; | |
| 114 | + u32 vsync_invert; | |
| 115 | + u32 invert_pixclock; | |
| 116 | + u32 pixclock_freq; | |
| 117 | + int pix_fmt_out; | |
| 118 | +}; | |
| 119 | + | |
| 120 | +/* main structures */ | |
| 121 | +struct mmp_path; | |
| 122 | +struct mmp_overlay; | |
| 123 | +struct mmp_panel; | |
| 124 | + | |
| 125 | +/* status types */ | |
| 126 | +enum { | |
| 127 | + MMP_OFF = 0, | |
| 128 | + MMP_ON, | |
| 129 | +}; | |
| 130 | + | |
| 131 | +static inline const char *stat_name(int stat) | |
| 132 | +{ | |
| 133 | + switch (stat) { | |
| 134 | + case MMP_OFF: | |
| 135 | + return "OFF"; | |
| 136 | + case MMP_ON: | |
| 137 | + return "ON"; | |
| 138 | + default: | |
| 139 | + return "UNKNOWNSTAT"; | |
| 140 | + } | |
| 141 | +} | |
| 142 | + | |
| 143 | +struct mmp_overlay_ops { | |
| 144 | + /* should be provided by driver */ | |
| 145 | + void (*set_fetch)(struct mmp_overlay *overlay, int fetch_id); | |
| 146 | + void (*set_onoff)(struct mmp_overlay *overlay, int status); | |
| 147 | + void (*set_win)(struct mmp_overlay *overlay, struct mmp_win *win); | |
| 148 | + int (*set_addr)(struct mmp_overlay *overlay, struct mmp_addr *addr); | |
| 149 | +}; | |
| 150 | + | |
| 151 | +/* overlay describes a z-order indexed slot in each path. */ | |
| 152 | +struct mmp_overlay { | |
| 153 | + int id; | |
| 154 | + const char *name; | |
| 155 | + struct mmp_path *path; | |
| 156 | + | |
| 157 | + /* overlay info: private data */ | |
| 158 | + int dmafetch_id; | |
| 159 | + struct mmp_addr addr; | |
| 160 | + struct mmp_win win; | |
| 161 | + | |
| 162 | + /* state */ | |
| 163 | + int open_count; | |
| 164 | + int status; | |
| 165 | + struct mutex access_ok; | |
| 166 | + | |
| 167 | + struct mmp_overlay_ops *ops; | |
| 168 | +}; | |
| 169 | + | |
| 170 | +/* panel type */ | |
| 171 | +enum { | |
| 172 | + PANELTYPE_ACTIVE = 0, | |
| 173 | + PANELTYPE_SMART, | |
| 174 | + PANELTYPE_TV, | |
| 175 | + PANELTYPE_DSI_CMD, | |
| 176 | + PANELTYPE_DSI_VIDEO, | |
| 177 | +}; | |
| 178 | + | |
| 179 | +struct mmp_panel { | |
| 180 | + /* use node to register to list */ | |
| 181 | + struct list_head node; | |
| 182 | + const char *name; | |
| 183 | + /* path name used to connect to proper path configed */ | |
| 184 | + const char *plat_path_name; | |
| 185 | + struct device *dev; | |
| 186 | + int panel_type; | |
| 187 | + void *plat_data; | |
| 188 | + int (*get_modelist)(struct mmp_panel *panel, | |
| 189 | + struct mmp_mode **modelist); | |
| 190 | + void (*set_mode)(struct mmp_panel *panel, | |
| 191 | + struct mmp_mode *mode); | |
| 192 | + void (*set_onoff)(struct mmp_panel *panel, | |
| 193 | + int status); | |
| 194 | +}; | |
| 195 | + | |
| 196 | +struct mmp_path_ops { | |
| 197 | + int (*check_status)(struct mmp_path *path); | |
| 198 | + struct mmp_overlay *(*get_overlay)(struct mmp_path *path, | |
| 199 | + int overlay_id); | |
| 200 | + int (*get_modelist)(struct mmp_path *path, | |
| 201 | + struct mmp_mode **modelist); | |
| 202 | + | |
| 203 | + /* follow ops should be provided by driver */ | |
| 204 | + void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode); | |
| 205 | + void (*set_onoff)(struct mmp_path *path, int status); | |
| 206 | + /* todo: add query */ | |
| 207 | +}; | |
| 208 | + | |
| 209 | +/* path output types */ | |
| 210 | +enum { | |
| 211 | + PATH_OUT_PARALLEL, | |
| 212 | + PATH_OUT_DSI, | |
| 213 | + PATH_OUT_HDMI, | |
| 214 | +}; | |
| 215 | + | |
| 216 | +/* path is main part of mmp-disp */ | |
| 217 | +struct mmp_path { | |
| 218 | + /* use node to register to list */ | |
| 219 | + struct list_head node; | |
| 220 | + | |
| 221 | + /* init data */ | |
| 222 | + struct device *dev; | |
| 223 | + | |
| 224 | + int id; | |
| 225 | + const char *name; | |
| 226 | + int output_type; | |
| 227 | + struct mmp_panel *panel; | |
| 228 | + void *plat_data; | |
| 229 | + | |
| 230 | + /* dynamic use */ | |
| 231 | + struct mmp_mode mode; | |
| 232 | + | |
| 233 | + /* state */ | |
| 234 | + int open_count; | |
| 235 | + int status; | |
| 236 | + struct mutex access_ok; | |
| 237 | + | |
| 238 | + struct mmp_path_ops ops; | |
| 239 | + | |
| 240 | + /* layers */ | |
| 241 | + int overlay_num; | |
| 242 | + struct mmp_overlay overlays[0]; | |
| 243 | +}; | |
| 244 | + | |
| 245 | +extern struct mmp_path *mmp_get_path(const char *name); | |
| 246 | +static inline void mmp_path_set_mode(struct mmp_path *path, | |
| 247 | + struct mmp_mode *mode) | |
| 248 | +{ | |
| 249 | + if (path) | |
| 250 | + path->ops.set_mode(path, mode); | |
| 251 | +} | |
| 252 | +static inline void mmp_path_set_onoff(struct mmp_path *path, int status) | |
| 253 | +{ | |
| 254 | + if (path) | |
| 255 | + path->ops.set_onoff(path, status); | |
| 256 | +} | |
| 257 | +static inline int mmp_path_get_modelist(struct mmp_path *path, | |
| 258 | + struct mmp_mode **modelist) | |
| 259 | +{ | |
| 260 | + if (path) | |
| 261 | + return path->ops.get_modelist(path, modelist); | |
| 262 | + return 0; | |
| 263 | +} | |
| 264 | +static inline struct mmp_overlay *mmp_path_get_overlay( | |
| 265 | + struct mmp_path *path, int overlay_id) | |
| 266 | +{ | |
| 267 | + if (path) | |
| 268 | + return path->ops.get_overlay(path, overlay_id); | |
| 269 | + return NULL; | |
| 270 | +} | |
| 271 | +static inline void mmp_overlay_set_fetch(struct mmp_overlay *overlay, | |
| 272 | + int fetch_id) | |
| 273 | +{ | |
| 274 | + if (overlay) | |
| 275 | + overlay->ops->set_fetch(overlay, fetch_id); | |
| 276 | +} | |
| 277 | +static inline void mmp_overlay_set_onoff(struct mmp_overlay *overlay, | |
| 278 | + int status) | |
| 279 | +{ | |
| 280 | + if (overlay) | |
| 281 | + overlay->ops->set_onoff(overlay, status); | |
| 282 | +} | |
| 283 | +static inline void mmp_overlay_set_win(struct mmp_overlay *overlay, | |
| 284 | + struct mmp_win *win) | |
| 285 | +{ | |
| 286 | + if (overlay) | |
| 287 | + overlay->ops->set_win(overlay, win); | |
| 288 | +} | |
| 289 | +static inline int mmp_overlay_set_addr(struct mmp_overlay *overlay, | |
| 290 | + struct mmp_addr *addr) | |
| 291 | +{ | |
| 292 | + if (overlay) | |
| 293 | + return overlay->ops->set_addr(overlay, addr); | |
| 294 | + return 0; | |
| 295 | +} | |
| 296 | + | |
| 297 | +/* | |
| 298 | + * driver data is set from each detailed ctrl driver for path usage | |
| 299 | + * it defined a common interface that plat driver need to implement | |
| 300 | + */ | |
| 301 | +struct mmp_path_info { | |
| 302 | + /* driver data, set when registed*/ | |
| 303 | + const char *name; | |
| 304 | + struct device *dev; | |
| 305 | + int id; | |
| 306 | + int output_type; | |
| 307 | + int overlay_num; | |
| 308 | + void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode); | |
| 309 | + void (*set_onoff)(struct mmp_path *path, int status); | |
| 310 | + struct mmp_overlay_ops *overlay_ops; | |
| 311 | + void *plat_data; | |
| 312 | +}; | |
| 313 | + | |
| 314 | +extern struct mmp_path *mmp_register_path( | |
| 315 | + struct mmp_path_info *info); | |
| 316 | +extern void mmp_unregister_path(struct mmp_path *path); | |
| 317 | +extern void mmp_register_panel(struct mmp_panel *panel); | |
| 318 | +extern void mmp_unregister_panel(struct mmp_panel *panel); | |
| 319 | + | |
| 320 | +/* defintions for platform data */ | |
| 321 | +/* interface for buffer driver */ | |
| 322 | +struct mmp_buffer_driver_mach_info { | |
| 323 | + const char *name; | |
| 324 | + const char *path_name; | |
| 325 | + int overlay_id; | |
| 326 | + int dmafetch_id; | |
| 327 | + int default_pixfmt; | |
| 328 | +}; | |
| 329 | + | |
| 330 | +/* interface for controllers driver */ | |
| 331 | +struct mmp_mach_path_config { | |
| 332 | + const char *name; | |
| 333 | + int overlay_num; | |
| 334 | + int output_type; | |
| 335 | + u32 path_config; | |
| 336 | + u32 link_config; | |
| 337 | +}; | |
| 338 | + | |
| 339 | +struct mmp_mach_plat_info { | |
| 340 | + const char *name; | |
| 341 | + const char *clk_name; | |
| 342 | + int path_num; | |
| 343 | + struct mmp_mach_path_config *paths; | |
| 344 | +}; | |
| 345 | + | |
| 346 | +/* interface for panel drivers */ | |
| 347 | +struct mmp_mach_panel_info { | |
| 348 | + const char *name; | |
| 349 | + void (*plat_set_onoff)(int status); | |
| 350 | + const char *plat_path_name; | |
| 351 | +}; | |
| 352 | +#endif /* _MMP_DISP_H_ */ | |
| @@ -8,12 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | * S3C Platform - new-style fimd and framebuffer register definitions |
| 9 | 9 | * |
| 10 | 10 | * This is the register set for the fimd and new style framebuffer interface |
| 11 | − * found from the S3C2443 onwards into the S3C2416, S3C2450 and the | |
| 12 | − * S3C64XX series such as the S3C6400 and S3C6410. | |
| 13 | − * | |
| 14 | − * The file does not contain the cpu specific items which are based on | |
| 15 | − * whichever architecture is selected, it only contains the core of the | |
| 16 | − * register set. See <mach/regs-fb.h> to get the specifics. | |
| 11 | + * found from the S3C2443 onwards into the S3C2416, S3C2450, the | |
| 12 | + * S3C64XX series such as the S3C6400 and S3C6410, and EXYNOS series. | |
| 17 | 13 | * |
| 18 | 14 | * This program is free software; you can redistribute it and/or modify |
| 19 | 15 | * it under the terms of the GNU General Public License version 2 as |
| @@ -22,10 +18,10 @@ · 2 unmodified lines | ||
| 22 | 18 | |
| 23 | 19 | /* VIDCON0 */ |
| 24 | 20 | |
| 25 | −#define VIDCON0 (0x00) | |
| 21 | +#define VIDCON0 0x00 | |
| 26 | 22 | #define VIDCON0_INTERLACE (1 << 29) |
| 27 | 23 | #define VIDCON0_VIDOUT_MASK (0x7 << 26) |
| 28 | −#define VIDCON0_VIDOUT_SHIFT (26) | |
| 24 | +#define VIDCON0_VIDOUT_SHIFT 26 | |
| 29 | 25 | #define VIDCON0_VIDOUT_RGB (0x0 << 26) |
| 30 | 26 | #define VIDCON0_VIDOUT_TV (0x1 << 26) |
| 31 | 27 | #define VIDCON0_VIDOUT_I80_LDI0 (0x2 << 26) |
| @@ -35,7 +31,7 @@ · 3 unmodified lines | ||
| 35 | 31 | #define VIDCON0_VIDOUT_WB_I80_LDI1 (0x7 << 26) |
| 36 | 32 | |
| 37 | 33 | #define VIDCON0_L1_DATA_MASK (0x7 << 23) |
| 38 | −#define VIDCON0_L1_DATA_SHIFT (23) | |
| 34 | +#define VIDCON0_L1_DATA_SHIFT 23 | |
| 39 | 35 | #define VIDCON0_L1_DATA_16BPP (0x0 << 23) |
| 40 | 36 | #define VIDCON0_L1_DATA_18BPP16 (0x1 << 23) |
| 41 | 37 | #define VIDCON0_L1_DATA_18BPP9 (0x2 << 23) |
| @@ -44,7 +40,7 @@ · 2 unmodified lines | ||
| 44 | 40 | #define VIDCON0_L1_DATA_16BPP8 (0x5 << 23) |
| 45 | 41 | |
| 46 | 42 | #define VIDCON0_L0_DATA_MASK (0x7 << 20) |
| 47 | −#define VIDCON0_L0_DATA_SHIFT (20) | |
| 43 | +#define VIDCON0_L0_DATA_SHIFT 20 | |
| 48 | 44 | #define VIDCON0_L0_DATA_16BPP (0x0 << 20) |
| 49 | 45 | #define VIDCON0_L0_DATA_18BPP16 (0x1 << 20) |
| 50 | 46 | #define VIDCON0_L0_DATA_18BPP9 (0x2 << 20) |
| @@ -53,7 +49,7 @@ · 2 unmodified lines | ||
| 53 | 49 | #define VIDCON0_L0_DATA_16BPP8 (0x5 << 20) |
| 54 | 50 | |
| 55 | 51 | #define VIDCON0_PNRMODE_MASK (0x3 << 17) |
| 56 | −#define VIDCON0_PNRMODE_SHIFT (17) | |
| 52 | +#define VIDCON0_PNRMODE_SHIFT 17 | |
| 57 | 53 | #define VIDCON0_PNRMODE_RGB (0x0 << 17) |
| 58 | 54 | #define VIDCON0_PNRMODE_BGR (0x1 << 17) |
| 59 | 55 | #define VIDCON0_PNRMODE_SERIAL_RGB (0x2 << 17) |
| @@ -61,14 +57,14 @@ · 1 unmodified line | ||
| 61 | 57 | |
| 62 | 58 | #define VIDCON0_CLKVALUP (1 << 16) |
| 63 | 59 | #define VIDCON0_CLKVAL_F_MASK (0xff << 6) |
| 64 | −#define VIDCON0_CLKVAL_F_SHIFT (6) | |
| 65 | −#define VIDCON0_CLKVAL_F_LIMIT (0xff) | |
| 60 | +#define VIDCON0_CLKVAL_F_SHIFT 6 | |
| 61 | +#define VIDCON0_CLKVAL_F_LIMIT 0xff | |
| 66 | 62 | #define VIDCON0_CLKVAL_F(_x) ((_x) << 6) |
| 67 | 63 | #define VIDCON0_VLCKFREE (1 << 5) |
| 68 | 64 | #define VIDCON0_CLKDIR (1 << 4) |
| 69 | 65 | |
| 70 | 66 | #define VIDCON0_CLKSEL_MASK (0x3 << 2) |
| 71 | −#define VIDCON0_CLKSEL_SHIFT (2) | |
| 67 | +#define VIDCON0_CLKSEL_SHIFT 2 | |
| 72 | 68 | #define VIDCON0_CLKSEL_HCLK (0x0 << 2) |
| 73 | 69 | #define VIDCON0_CLKSEL_LCD (0x1 << 2) |
| 74 | 70 | #define VIDCON0_CLKSEL_27M (0x3 << 2) |
| @@ -76,17 +72,17 @@ · 1 unmodified line | ||
| 76 | 72 | #define VIDCON0_ENVID (1 << 1) |
| 77 | 73 | #define VIDCON0_ENVID_F (1 << 0) |
| 78 | 74 | |
| 79 | −#define VIDCON1 (0x04) | |
| 75 | +#define VIDCON1 0x04 | |
| 80 | 76 | #define VIDCON1_LINECNT_MASK (0x7ff << 16) |
| 81 | −#define VIDCON1_LINECNT_SHIFT (16) | |
| 77 | +#define VIDCON1_LINECNT_SHIFT 16 | |
| 82 | 78 | #define VIDCON1_LINECNT_GET(_v) (((_v) >> 16) & 0x7ff) |
| 83 | 79 | #define VIDCON1_FSTATUS_EVEN (1 << 15) |
| 84 | 80 | #define VIDCON1_VSTATUS_MASK (0x3 << 13) |
| 85 | −#define VIDCON1_VSTATUS_SHIFT (13) | |
| 81 | +#define VIDCON1_VSTATUS_SHIFT 13 | |
| 86 | 82 | #define VIDCON1_VSTATUS_VSYNC (0x0 << 13) |
| 87 | 83 | #define VIDCON1_VSTATUS_BACKPORCH (0x1 << 13) |
| 88 | 84 | #define VIDCON1_VSTATUS_ACTIVE (0x2 << 13) |
| 89 | −#define VIDCON1_VSTATUS_FRONTPORCH (0x0 << 13) | |
| 85 | +#define VIDCON1_VSTATUS_FRONTPORCH (0x3 << 13) | |
| 90 | 86 | #define VIDCON1_VCLK_MASK (0x3 << 9) |
| 91 | 87 | #define VIDCON1_VCLK_HOLD (0x0 << 9) |
| 92 | 88 | #define VIDCON1_VCLK_RUN (0x1 << 9) |
| @@ -98,12 +94,12 @@ · 5 unmodified lines | ||
| 98 | 94 | |
| 99 | 95 | /* VIDCON2 */ |
| 100 | 96 | |
| 101 | −#define VIDCON2 (0x08) | |
| 97 | +#define VIDCON2 0x08 | |
| 102 | 98 | #define VIDCON2_EN601 (1 << 23) |
| 103 | 99 | #define VIDCON2_TVFMTSEL_SW (1 << 14) |
| 104 | 100 | |
| 105 | 101 | #define VIDCON2_TVFMTSEL1_MASK (0x3 << 12) |
| 106 | −#define VIDCON2_TVFMTSEL1_SHIFT (12) | |
| 102 | +#define VIDCON2_TVFMTSEL1_SHIFT 12 | |
| 107 | 103 | #define VIDCON2_TVFMTSEL1_RGB (0x0 << 12) |
| 108 | 104 | #define VIDCON2_TVFMTSEL1_YUV422 (0x1 << 12) |
| 109 | 105 | #define VIDCON2_TVFMTSEL1_YUV444 (0x2 << 12) |
| @@ -115,74 +111,75 @@ · 5 unmodified lines | ||
| 115 | 111 | * Might not be present in the S3C6410 documentation, |
| 116 | 112 | * but tests prove it's there almost for sure; shouldn't hurt in any case. |
| 117 | 113 | */ |
| 118 | −#define PRTCON (0x0c) | |
| 114 | +#define PRTCON 0x0c | |
| 119 | 115 | #define PRTCON_PROTECT (1 << 11) |
| 120 | 116 | |
| 121 | 117 | /* VIDTCON0 */ |
| 122 | 118 | |
| 123 | −#define VIDTCON0 (0x10) | |
| 119 | +#define VIDTCON0 0x10 | |
| 124 | 120 | #define VIDTCON0_VBPDE_MASK (0xff << 24) |
| 125 | −#define VIDTCON0_VBPDE_SHIFT (24) | |
| 126 | −#define VIDTCON0_VBPDE_LIMIT (0xff) | |
| 121 | +#define VIDTCON0_VBPDE_SHIFT 24 | |
| 122 | +#define VIDTCON0_VBPDE_LIMIT 0xff | |
| 127 | 123 | #define VIDTCON0_VBPDE(_x) ((_x) << 24) |
| 128 | 124 | |
| 129 | 125 | #define VIDTCON0_VBPD_MASK (0xff << 16) |
| 130 | −#define VIDTCON0_VBPD_SHIFT (16) | |
| 131 | −#define VIDTCON0_VBPD_LIMIT (0xff) | |
| 126 | +#define VIDTCON0_VBPD_SHIFT 16 | |
| 127 | +#define VIDTCON0_VBPD_LIMIT 0xff | |
| 132 | 128 | #define VIDTCON0_VBPD(_x) ((_x) << 16) |
| 133 | 129 | |
| 134 | 130 | #define VIDTCON0_VFPD_MASK (0xff << 8) |
| 135 | −#define VIDTCON0_VFPD_SHIFT (8) | |
| 136 | −#define VIDTCON0_VFPD_LIMIT (0xff) | |
| 131 | +#define VIDTCON0_VFPD_SHIFT 8 | |
| 132 | +#define VIDTCON0_VFPD_LIMIT 0xff | |
| 137 | 133 | #define VIDTCON0_VFPD(_x) ((_x) << 8) |
| 138 | 134 | |
| 139 | 135 | #define VIDTCON0_VSPW_MASK (0xff << 0) |
| 140 | −#define VIDTCON0_VSPW_SHIFT (0) | |
| 141 | −#define VIDTCON0_VSPW_LIMIT (0xff) | |
| 136 | +#define VIDTCON0_VSPW_SHIFT 0 | |
| 137 | +#define VIDTCON0_VSPW_LIMIT 0xff | |
| 142 | 138 | #define VIDTCON0_VSPW(_x) ((_x) << 0) |
| 143 | 139 | |
| 144 | 140 | /* VIDTCON1 */ |
| 145 | 141 | |
| 146 | −#define VIDTCON1 (0x14) | |
| 142 | +#define VIDTCON1 0x14 | |
| 147 | 143 | #define VIDTCON1_VFPDE_MASK (0xff << 24) |
| 148 | −#define VIDTCON1_VFPDE_SHIFT (24) | |
| 149 | −#define VIDTCON1_VFPDE_LIMIT (0xff) | |
| 144 | +#define VIDTCON1_VFPDE_SHIFT 24 | |
| 145 | +#define VIDTCON1_VFPDE_LIMIT 0xff | |
| 150 | 146 | #define VIDTCON1_VFPDE(_x) ((_x) << 24) |
| 151 | 147 | |
| 152 | 148 | #define VIDTCON1_HBPD_MASK (0xff << 16) |
| 153 | −#define VIDTCON1_HBPD_SHIFT (16) | |
| 154 | −#define VIDTCON1_HBPD_LIMIT (0xff) | |
| 149 | +#define VIDTCON1_HBPD_SHIFT 16 | |
| 150 | +#define VIDTCON1_HBPD_LIMIT 0xff | |
| 155 | 151 | #define VIDTCON1_HBPD(_x) ((_x) << 16) |
| 156 | 152 | |
| 157 | 153 | #define VIDTCON1_HFPD_MASK (0xff << 8) |
| 158 | −#define VIDTCON1_HFPD_SHIFT (8) | |
| 159 | −#define VIDTCON1_HFPD_LIMIT (0xff) | |
| 154 | +#define VIDTCON1_HFPD_SHIFT 8 | |
| 155 | +#define VIDTCON1_HFPD_LIMIT 0xff | |
| 160 | 156 | #define VIDTCON1_HFPD(_x) ((_x) << 8) |
| 161 | 157 | |
| 162 | 158 | #define VIDTCON1_HSPW_MASK (0xff << 0) |
| 163 | −#define VIDTCON1_HSPW_SHIFT (0) | |
| 164 | −#define VIDTCON1_HSPW_LIMIT (0xff) | |
| 159 | +#define VIDTCON1_HSPW_SHIFT 0 | |
| 160 | +#define VIDTCON1_HSPW_LIMIT 0xff | |
| 165 | 161 | #define VIDTCON1_HSPW(_x) ((_x) << 0) |
| 166 | 162 | |
| 167 | −#define VIDTCON2 (0x18) | |
| 168 | −#define VIDTCON2 (0x18) | |
| 163 | +#define VIDTCON2 0x18 | |
| 169 | 164 | #define VIDTCON2_LINEVAL_E(_x) ((((_x) & 0x800) >> 11) << 23) |
| 170 | 165 | #define VIDTCON2_LINEVAL_MASK (0x7ff << 11) |
| 171 | −#define VIDTCON2_LINEVAL_SHIFT (11) | |
| 172 | −#define VIDTCON2_LINEVAL_LIMIT (0x7ff) | |
| 166 | +#define VIDTCON2_LINEVAL_SHIFT 11 | |
| 167 | +#define VIDTCON2_LINEVAL_LIMIT 0x7ff | |
| 173 | 168 | #define VIDTCON2_LINEVAL(_x) (((_x) & 0x7ff) << 11) |
| 174 | 169 | |
| 175 | 170 | #define VIDTCON2_HOZVAL_E(_x) ((((_x) & 0x800) >> 11) << 22) |
| 176 | 171 | #define VIDTCON2_HOZVAL_MASK (0x7ff << 0) |
| 177 | −#define VIDTCON2_HOZVAL_SHIFT (0) | |
| 178 | −#define VIDTCON2_HOZVAL_LIMIT (0x7ff) | |
| 172 | +#define VIDTCON2_HOZVAL_SHIFT 0 | |
| 173 | +#define VIDTCON2_HOZVAL_LIMIT 0x7ff | |
| 179 | 174 | #define VIDTCON2_HOZVAL(_x) (((_x) & 0x7ff) << 0) |
| 180 | 175 | |
| 181 | 176 | /* WINCONx */ |
| 182 | 177 | |
| 183 | 178 | #define WINCON(_win) (0x20 + ((_win) * 4)) |
| 179 | +#define WINCONx_CSCCON_EQ601 (0x0 << 28) | |
| 180 | +#define WINCONx_CSCCON_EQ709 (0x1 << 28) | |
| 184 | 181 | #define WINCONx_CSCWIDTH_MASK (0x3 << 26) |
| 185 | −#define WINCONx_CSCWIDTH_SHIFT (26) | |
| 182 | +#define WINCONx_CSCWIDTH_SHIFT 26 | |
| 186 | 183 | #define WINCONx_CSCWIDTH_WIDE (0x0 << 26) |
| 187 | 184 | #define WINCONx_CSCWIDTH_NARROW (0x3 << 26) |
| 188 | 185 | #define WINCONx_ENLOCAL (1 << 22) |
| @@ -195,14 +192,14 @@ · 6 unmodified lines | ||
| 195 | 192 | #define WINCONx_WSWP (1 << 15) |
| 196 | 193 | #define WINCONx_YCbCr (1 << 13) |
| 197 | 194 | #define WINCONx_BURSTLEN_MASK (0x3 << 9) |
| 198 | −#define WINCONx_BURSTLEN_SHIFT (9) | |
| 195 | +#define WINCONx_BURSTLEN_SHIFT 9 | |
| 199 | 196 | #define WINCONx_BURSTLEN_16WORD (0x0 << 9) |
| 200 | 197 | #define WINCONx_BURSTLEN_8WORD (0x1 << 9) |
| 201 | 198 | #define WINCONx_BURSTLEN_4WORD (0x2 << 9) |
| 202 | 199 | #define WINCONx_ENWIN (1 << 0) |
| 203 | 200 | |
| 204 | 201 | #define WINCON0_BPPMODE_MASK (0xf << 2) |
| 205 | −#define WINCON0_BPPMODE_SHIFT (2) | |
| 202 | +#define WINCON0_BPPMODE_SHIFT 2 | |
| 206 | 203 | #define WINCON0_BPPMODE_1BPP (0x0 << 2) |
| 207 | 204 | #define WINCON0_BPPMODE_2BPP (0x1 << 2) |
| 208 | 205 | #define WINCON0_BPPMODE_4BPP (0x2 << 2) |
| @@ -215,7 +212,7 @@ · 6 unmodified lines | ||
| 215 | 212 | #define WINCON1_LOCALSEL_CAMIF (1 << 23) |
| 216 | 213 | #define WINCON1_BLD_PIX (1 << 6) |
| 217 | 214 | #define WINCON1_BPPMODE_MASK (0xf << 2) |
| 218 | −#define WINCON1_BPPMODE_SHIFT (2) | |
| 215 | +#define WINCON1_BPPMODE_SHIFT 2 | |
| 219 | 216 | #define WINCON1_BPPMODE_1BPP (0x0 << 2) |
| 220 | 217 | #define WINCON1_BPPMODE_2BPP (0x1 << 2) |
| 221 | 218 | #define WINCON1_BPPMODE_4BPP (0x2 << 2) |
| @@ -234,7 +231,7 @@ · 12 unmodified lines | ||
| 234 | 231 | #define WINCON1_ALPHA_SEL (1 << 1) |
| 235 | 232 | |
| 236 | 233 | /* S5PV210 */ |
| 237 | −#define SHADOWCON (0x34) | |
| 234 | +#define SHADOWCON 0x34 | |
| 238 | 235 | #define SHADOWCON_WINx_PROTECT(_win) (1 << (10 + (_win))) |
| 239 | 236 | /* DMA channels (all windows) */ |
| 240 | 237 | #define SHADOWCON_CHx_ENABLE(_win) (1 << (_win)) |
| @@ -243,52 +240,52 @@ · 2 unmodified lines | ||
| 243 | 240 | |
| 244 | 241 | /* VIDOSDx */ |
| 245 | 242 | |
| 246 | −#define VIDOSD_BASE (0x40) | |
| 243 | +#define VIDOSD_BASE 0x40 | |
| 247 | 244 | #define VIDOSDxA_TOPLEFT_X_E(_x) ((((_x) & 0x800) >> 11) << 23) |
| 248 | 245 | #define VIDOSDxA_TOPLEFT_X_MASK (0x7ff << 11) |
| 249 | −#define VIDOSDxA_TOPLEFT_X_SHIFT (11) | |
| 250 | −#define VIDOSDxA_TOPLEFT_X_LIMIT (0x7ff) | |
| 246 | +#define VIDOSDxA_TOPLEFT_X_SHIFT 11 | |
| 247 | +#define VIDOSDxA_TOPLEFT_X_LIMIT 0x7ff | |
| 251 | 248 | #define VIDOSDxA_TOPLEFT_X(_x) (((_x) & 0x7ff) << 11) |
| 252 | 249 | |
| 253 | 250 | #define VIDOSDxA_TOPLEFT_Y_E(_x) ((((_x) & 0x800) >> 11) << 22) |
| 254 | 251 | #define VIDOSDxA_TOPLEFT_Y_MASK (0x7ff << 0) |
| 255 | −#define VIDOSDxA_TOPLEFT_Y_SHIFT (0) | |
| 256 | −#define VIDOSDxA_TOPLEFT_Y_LIMIT (0x7ff) | |
| 252 | +#define VIDOSDxA_TOPLEFT_Y_SHIFT 0 | |
| 253 | +#define VIDOSDxA_TOPLEFT_Y_LIMIT 0x7ff | |
| 257 | 254 | #define VIDOSDxA_TOPLEFT_Y(_x) (((_x) & 0x7ff) << 0) |
| 258 | 255 | |
| 259 | 256 | #define VIDOSDxB_BOTRIGHT_X_E(_x) ((((_x) & 0x800) >> 11) << 23) |
| 260 | 257 | #define VIDOSDxB_BOTRIGHT_X_MASK (0x7ff << 11) |
| 261 | −#define VIDOSDxB_BOTRIGHT_X_SHIFT (11) | |
| 262 | −#define VIDOSDxB_BOTRIGHT_X_LIMIT (0x7ff) | |
| 258 | +#define VIDOSDxB_BOTRIGHT_X_SHIFT 11 | |
| 259 | +#define VIDOSDxB_BOTRIGHT_X_LIMIT 0x7ff | |
| 263 | 260 | #define VIDOSDxB_BOTRIGHT_X(_x) (((_x) & 0x7ff) << 11) |
| 264 | 261 | |
| 265 | 262 | #define VIDOSDxB_BOTRIGHT_Y_E(_x) ((((_x) & 0x800) >> 11) << 22) |
| 266 | 263 | #define VIDOSDxB_BOTRIGHT_Y_MASK (0x7ff << 0) |
| 267 | −#define VIDOSDxB_BOTRIGHT_Y_SHIFT (0) | |
| 268 | −#define VIDOSDxB_BOTRIGHT_Y_LIMIT (0x7ff) | |
| 264 | +#define VIDOSDxB_BOTRIGHT_Y_SHIFT 0 | |
| 265 | +#define VIDOSDxB_BOTRIGHT_Y_LIMIT 0x7ff | |
| 269 | 266 | #define VIDOSDxB_BOTRIGHT_Y(_x) (((_x) & 0x7ff) << 0) |
| 270 | 267 | |
| 271 | 268 | /* For VIDOSD[1..4]C */ |
| 272 | 269 | #define VIDISD14C_ALPHA0_R(_x) ((_x) << 20) |
| 273 | 270 | #define VIDISD14C_ALPHA0_G_MASK (0xf << 16) |
| 274 | −#define VIDISD14C_ALPHA0_G_SHIFT (16) | |
| 275 | −#define VIDISD14C_ALPHA0_G_LIMIT (0xf) | |
| 271 | +#define VIDISD14C_ALPHA0_G_SHIFT 16 | |
| 272 | +#define VIDISD14C_ALPHA0_G_LIMIT 0xf | |
| 276 | 273 | #define VIDISD14C_ALPHA0_G(_x) ((_x) << 16) |
| 277 | 274 | #define VIDISD14C_ALPHA0_B_MASK (0xf << 12) |
| 278 | −#define VIDISD14C_ALPHA0_B_SHIFT (12) | |
| 279 | −#define VIDISD14C_ALPHA0_B_LIMIT (0xf) | |
| 275 | +#define VIDISD14C_ALPHA0_B_SHIFT 12 | |
| 276 | +#define VIDISD14C_ALPHA0_B_LIMIT 0xf | |
| 280 | 277 | #define VIDISD14C_ALPHA0_B(_x) ((_x) << 12) |
| 281 | 278 | #define VIDISD14C_ALPHA1_R_MASK (0xf << 8) |
| 282 | −#define VIDISD14C_ALPHA1_R_SHIFT (8) | |
| 283 | −#define VIDISD14C_ALPHA1_R_LIMIT (0xf) | |
| 279 | +#define VIDISD14C_ALPHA1_R_SHIFT 8 | |
| 280 | +#define VIDISD14C_ALPHA1_R_LIMIT 0xf | |
| 284 | 281 | #define VIDISD14C_ALPHA1_R(_x) ((_x) << 8) |
| 285 | 282 | #define VIDISD14C_ALPHA1_G_MASK (0xf << 4) |
| 286 | −#define VIDISD14C_ALPHA1_G_SHIFT (4) | |
| 287 | −#define VIDISD14C_ALPHA1_G_LIMIT (0xf) | |
| 283 | +#define VIDISD14C_ALPHA1_G_SHIFT 4 | |
| 284 | +#define VIDISD14C_ALPHA1_G_LIMIT 0xf | |
| 288 | 285 | #define VIDISD14C_ALPHA1_G(_x) ((_x) << 4) |
| 289 | 286 | #define VIDISD14C_ALPHA1_B_MASK (0xf << 0) |
| 290 | −#define VIDISD14C_ALPHA1_B_SHIFT (0) | |
| 291 | −#define VIDISD14C_ALPHA1_B_LIMIT (0xf) | |
| 287 | +#define VIDISD14C_ALPHA1_B_SHIFT 0 | |
| 288 | +#define VIDISD14C_ALPHA1_B_LIMIT 0xf | |
| 292 | 289 | #define VIDISD14C_ALPHA1_B(_x) ((_x) << 0) |
| 293 | 290 | |
| 294 | 291 | /* Video buffer addresses */ |
| @@ -300,22 +297,22 @@ · 5 unmodified lines | ||
| 300 | 297 | |
| 301 | 298 | #define VIDW_BUF_SIZE_OFFSET_E(_x) ((((_x) & 0x2000) >> 13) << 27) |
| 302 | 299 | #define VIDW_BUF_SIZE_OFFSET_MASK (0x1fff << 13) |
| 303 | −#define VIDW_BUF_SIZE_OFFSET_SHIFT (13) | |
| 304 | −#define VIDW_BUF_SIZE_OFFSET_LIMIT (0x1fff) | |
| 300 | +#define VIDW_BUF_SIZE_OFFSET_SHIFT 13 | |
| 301 | +#define VIDW_BUF_SIZE_OFFSET_LIMIT 0x1fff | |
| 305 | 302 | #define VIDW_BUF_SIZE_OFFSET(_x) (((_x) & 0x1fff) << 13) |
| 306 | 303 | |
| 307 | 304 | #define VIDW_BUF_SIZE_PAGEWIDTH_E(_x) ((((_x) & 0x2000) >> 13) << 26) |
| 308 | 305 | #define VIDW_BUF_SIZE_PAGEWIDTH_MASK (0x1fff << 0) |
| 309 | −#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT (0) | |
| 310 | −#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT (0x1fff) | |
| 306 | +#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT 0 | |
| 307 | +#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT 0x1fff | |
| 311 | 308 | #define VIDW_BUF_SIZE_PAGEWIDTH(_x) (((_x) & 0x1fff) << 0) |
| 312 | 309 | |
| 313 | 310 | /* Interrupt controls and status */ |
| 314 | 311 | |
| 315 | −#define VIDINTCON0 (0x130) | |
| 312 | +#define VIDINTCON0 0x130 | |
| 316 | 313 | #define VIDINTCON0_FIFOINTERVAL_MASK (0x3f << 20) |
| 317 | −#define VIDINTCON0_FIFOINTERVAL_SHIFT (20) | |
| 318 | −#define VIDINTCON0_FIFOINTERVAL_LIMIT (0x3f) | |
| 314 | +#define VIDINTCON0_FIFOINTERVAL_SHIFT 20 | |
| 315 | +#define VIDINTCON0_FIFOINTERVAL_LIMIT 0x3f | |
| 319 | 316 | #define VIDINTCON0_FIFOINTERVAL(_x) ((_x) << 20) |
| 320 | 317 | |
| 321 | 318 | #define VIDINTCON0_INT_SYSMAINCON (1 << 19) |
| @@ -323,7 +320,7 @@ · 1 unmodified line | ||
| 323 | 320 | #define VIDINTCON0_INT_I80IFDONE (1 << 17) |
| 324 | 321 | |
| 325 | 322 | #define VIDINTCON0_FRAMESEL0_MASK (0x3 << 15) |
| 326 | −#define VIDINTCON0_FRAMESEL0_SHIFT (15) | |
| 323 | +#define VIDINTCON0_FRAMESEL0_SHIFT 15 | |
| 327 | 324 | #define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15) |
| 328 | 325 | #define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15) |
| 329 | 326 | #define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15) |
| @@ -338,7 +335,7 @@ · 8 unmodified lines | ||
| 338 | 335 | |
| 339 | 336 | #define VIDINTCON0_INT_FRAME (1 << 12) |
| 340 | 337 | #define VIDINTCON0_FIFIOSEL_MASK (0x7f << 5) |
| 341 | −#define VIDINTCON0_FIFIOSEL_SHIFT (5) | |
| 338 | +#define VIDINTCON0_FIFIOSEL_SHIFT 5 | |
| 342 | 339 | #define VIDINTCON0_FIFIOSEL_WINDOW0 (0x1 << 5) |
| 343 | 340 | #define VIDINTCON0_FIFIOSEL_WINDOW1 (0x2 << 5) |
| 344 | 341 | #define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5) |
| @@ -346,7 +343,7 @@ · 1 unmodified line | ||
| 346 | 343 | #define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5) |
| 347 | 344 | |
| 348 | 345 | #define VIDINTCON0_FIFOLEVEL_MASK (0x7 << 2) |
| 349 | −#define VIDINTCON0_FIFOLEVEL_SHIFT (2) | |
| 346 | +#define VIDINTCON0_FIFOLEVEL_SHIFT 2 | |
| 350 | 347 | #define VIDINTCON0_FIFOLEVEL_TO25PC (0x0 << 2) |
| 351 | 348 | #define VIDINTCON0_FIFOLEVEL_TO50PC (0x1 << 2) |
| 352 | 349 | #define VIDINTCON0_FIFOLEVEL_TO75PC (0x2 << 2) |
| @@ -354,46 +351,46 @@ · 1 unmodified line | ||
| 354 | 351 | #define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 2) |
| 355 | 352 | |
| 356 | 353 | #define VIDINTCON0_INT_FIFO_MASK (0x3 << 0) |
| 357 | −#define VIDINTCON0_INT_FIFO_SHIFT (0) | |
| 354 | +#define VIDINTCON0_INT_FIFO_SHIFT 0 | |
| 358 | 355 | #define VIDINTCON0_INT_ENABLE (1 << 0) |
| 359 | 356 | |
| 360 | −#define VIDINTCON1 (0x134) | |
| 357 | +#define VIDINTCON1 0x134 | |
| 361 | 358 | #define VIDINTCON1_INT_I180 (1 << 2) |
| 362 | 359 | #define VIDINTCON1_INT_FRAME (1 << 1) |
| 363 | 360 | #define VIDINTCON1_INT_FIFO (1 << 0) |
| 364 | 361 | |
| 365 | 362 | /* Window colour-key control registers */ |
| 366 | −#define WKEYCON (0x140) /* 6410,V210 */ | |
| 363 | +#define WKEYCON 0x140 | |
| 367 | 364 | |
| 368 | −#define WKEYCON0 (0x00) | |
| 369 | −#define WKEYCON1 (0x04) | |
| 365 | +#define WKEYCON0 0x00 | |
| 366 | +#define WKEYCON1 0x04 | |
| 370 | 367 | |
| 371 | 368 | #define WxKEYCON0_KEYBL_EN (1 << 26) |
| 372 | 369 | #define WxKEYCON0_KEYEN_F (1 << 25) |
| 373 | 370 | #define WxKEYCON0_DIRCON (1 << 24) |
| 374 | 371 | #define WxKEYCON0_COMPKEY_MASK (0xffffff << 0) |
| 375 | −#define WxKEYCON0_COMPKEY_SHIFT (0) | |
| 376 | −#define WxKEYCON0_COMPKEY_LIMIT (0xffffff) | |
| 372 | +#define WxKEYCON0_COMPKEY_SHIFT 0 | |
| 373 | +#define WxKEYCON0_COMPKEY_LIMIT 0xffffff | |
| 377 | 374 | #define WxKEYCON0_COMPKEY(_x) ((_x) << 0) |
| 378 | 375 | #define WxKEYCON1_COLVAL_MASK (0xffffff << 0) |
| 379 | −#define WxKEYCON1_COLVAL_SHIFT (0) | |
| 380 | −#define WxKEYCON1_COLVAL_LIMIT (0xffffff) | |
| 376 | +#define WxKEYCON1_COLVAL_SHIFT 0 | |
| 377 | +#define WxKEYCON1_COLVAL_LIMIT 0xffffff | |
| 381 | 378 | #define WxKEYCON1_COLVAL(_x) ((_x) << 0) |
| 382 | 379 | |
| 383 | 380 | /* Dithering control */ |
| 384 | −#define DITHMODE (0x170) | |
| 381 | +#define DITHMODE 0x170 | |
| 385 | 382 | #define DITHMODE_R_POS_MASK (0x3 << 5) |
| 386 | −#define DITHMODE_R_POS_SHIFT (5) | |
| 383 | +#define DITHMODE_R_POS_SHIFT 5 | |
| 387 | 384 | #define DITHMODE_R_POS_8BIT (0x0 << 5) |
| 388 | 385 | #define DITHMODE_R_POS_6BIT (0x1 << 5) |
| 389 | 386 | #define DITHMODE_R_POS_5BIT (0x2 << 5) |
| 390 | 387 | #define DITHMODE_G_POS_MASK (0x3 << 3) |
| 391 | −#define DITHMODE_G_POS_SHIFT (3) | |
| 388 | +#define DITHMODE_G_POS_SHIFT 3 | |
| 392 | 389 | #define DITHMODE_G_POS_8BIT (0x0 << 3) |
| 393 | 390 | #define DITHMODE_G_POS_6BIT (0x1 << 3) |
| 394 | 391 | #define DITHMODE_G_POS_5BIT (0x2 << 3) |
| 395 | 392 | #define DITHMODE_B_POS_MASK (0x3 << 1) |
| 396 | −#define DITHMODE_B_POS_SHIFT (1) | |
| 393 | +#define DITHMODE_B_POS_SHIFT 1 | |
| 397 | 394 | #define DITHMODE_B_POS_8BIT (0x0 << 1) |
| 398 | 395 | #define DITHMODE_B_POS_6BIT (0x1 << 1) |
| 399 | 396 | #define DITHMODE_B_POS_5BIT (0x2 << 1) |
| @@ -403,18 +400,18 @@ · 3 unmodified lines | ||
| 403 | 400 | #define WINxMAP(_win) (0x180 + ((_win) * 4)) |
| 404 | 401 | #define WINxMAP_MAP (1 << 24) |
| 405 | 402 | #define WINxMAP_MAP_COLOUR_MASK (0xffffff << 0) |
| 406 | −#define WINxMAP_MAP_COLOUR_SHIFT (0) | |
| 407 | −#define WINxMAP_MAP_COLOUR_LIMIT (0xffffff) | |
| 403 | +#define WINxMAP_MAP_COLOUR_SHIFT 0 | |
| 404 | +#define WINxMAP_MAP_COLOUR_LIMIT 0xffffff | |
| 408 | 405 | #define WINxMAP_MAP_COLOUR(_x) ((_x) << 0) |
| 409 | 406 | |
| 410 | 407 | /* Winodw palette control */ |
| 411 | −#define WPALCON (0x1A0) | |
| 408 | +#define WPALCON 0x1A0 | |
| 412 | 409 | #define WPALCON_PAL_UPDATE (1 << 9) |
| 413 | 410 | #define WPALCON_W4PAL_16BPP_A555 (1 << 8) |
| 414 | 411 | #define WPALCON_W3PAL_16BPP_A555 (1 << 7) |
| 415 | 412 | #define WPALCON_W2PAL_16BPP_A555 (1 << 6) |
| 416 | 413 | #define WPALCON_W1PAL_MASK (0x7 << 3) |
| 417 | −#define WPALCON_W1PAL_SHIFT (3) | |
| 414 | +#define WPALCON_W1PAL_SHIFT 3 | |
| 418 | 415 | #define WPALCON_W1PAL_25BPP_A888 (0x0 << 3) |
| 419 | 416 | #define WPALCON_W1PAL_24BPP (0x1 << 3) |
| 420 | 417 | #define WPALCON_W1PAL_19BPP_A666 (0x2 << 3) |
| @@ -423,7 +420,7 @@ · 2 unmodified lines | ||
| 423 | 420 | #define WPALCON_W1PAL_16BPP_A555 (0x5 << 3) |
| 424 | 421 | #define WPALCON_W1PAL_16BPP_565 (0x6 << 3) |
| 425 | 422 | #define WPALCON_W0PAL_MASK (0x7 << 0) |
| 426 | −#define WPALCON_W0PAL_SHIFT (0) | |
| 423 | +#define WPALCON_W0PAL_SHIFT 0 | |
| 427 | 424 | #define WPALCON_W0PAL_25BPP_A888 (0x0 << 0) |
| 428 | 425 | #define WPALCON_W0PAL_24BPP (0x1 << 0) |
| 429 | 426 | #define WPALCON_W0PAL_19BPP_A666 (0x2 << 0) |
| @@ -433,13 +430,11 @@ · 3 unmodified lines | ||
| 433 | 430 | #define WPALCON_W0PAL_16BPP_565 (0x6 << 0) |
| 434 | 431 | |
| 435 | 432 | /* Blending equation control */ |
| 436 | −#define BLENDCON (0x260) | |
| 433 | +#define BLENDCON 0x260 | |
| 437 | 434 | #define BLENDCON_NEW_MASK (1 << 0) |
| 438 | 435 | #define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0) |
| 439 | 436 | #define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0) |
| 440 | 437 | |
| 441 | −#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */ | |
| 442 | − | |
| 443 | 438 | /* Notes on per-window bpp settings |
| 444 | 439 | * |
| 445 | 440 | * Value Win0 Win1 Win2 Win3 Win 4 |
| @@ -462,8 +457,8 @@ · 16 unmodified lines | ||
| 462 | 457 | */ |
| 463 | 458 | |
| 464 | 459 | /* FIMD Version 8 register offset definitions */ |
| 465 | −#define FIMD_V8_VIDTCON0 (0x20010) | |
| 466 | −#define FIMD_V8_VIDTCON1 (0x20014) | |
| 467 | −#define FIMD_V8_VIDTCON2 (0x20018) | |
| 468 | −#define FIMD_V8_VIDTCON3 (0x2001C) | |
| 469 | −#define FIMD_V8_VIDCON1 (0x20004) | |
| 460 | +#define FIMD_V8_VIDTCON0 0x20010 | |
| 461 | +#define FIMD_V8_VIDTCON1 0x20014 | |
| 462 | +#define FIMD_V8_VIDTCON2 0x20018 | |
| 463 | +#define FIMD_V8_VIDTCON3 0x2001C | |
| 464 | +#define FIMD_V8_VIDCON1 0x20004 | |
| @@ -593,7 +593,7 @@ COMPAT_SYSCALL_DEFINE5(waitid, · 592 unmodified lines | ||
| 593 | 593 | else |
| 594 | 594 | ret = put_compat_rusage(&ru, uru); |
| 595 | 595 | if (ret) |
| 596 | − return ret; | |
| 596 | + return -EFAULT; | |
| 597 | 597 | } |
| 598 | 598 | |
| 599 | 599 | BUG_ON(info.si_code & __SI_MASK); |
| @@ -153,8 +153,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) · 152 unmodified lines | ||
| 153 | 153 | goto out; |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | − new_ns = create_new_namespaces(flags, tsk, | |
| 157 | − task_cred_xxx(tsk, user_ns), tsk->fs); | |
| 156 | + new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); | |
| 158 | 157 | if (IS_ERR(new_ns)) { |
| 159 | 158 | err = PTR_ERR(new_ns); |
| 160 | 159 | goto out; |
| @@ -16,22 +16,12 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "smpboot.h" |
| 17 | 17 | |
| 18 | 18 | #ifdef CONFIG_USE_GENERIC_SMP_HELPERS |
| 19 | −static struct { | |
| 20 | − struct list_head queue; | |
| 21 | − raw_spinlock_t lock; | |
| 22 | −} call_function __cacheline_aligned_in_smp = | |
| 23 | − { | |
| 24 | − .queue = LIST_HEAD_INIT(call_function.queue), | |
| 25 | − .lock = __RAW_SPIN_LOCK_UNLOCKED(call_function.lock), | |
| 26 | − }; | |
| 27 | − | |
| 28 | 19 | enum { |
| 29 | 20 | CSD_FLAG_LOCK = 0x01, |
| 30 | 21 | }; |
| 31 | 22 | |
| 32 | 23 | struct call_function_data { |
| 33 | − struct call_single_data csd; | |
| 34 | − atomic_t refs; | |
| 24 | + struct call_single_data __percpu *csd; | |
| 35 | 25 | cpumask_var_t cpumask; |
| 36 | 26 | cpumask_var_t cpumask_ipi; |
| 37 | 27 | }; |
| @@ -60,6 +50,11 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) · 22 unmodified lines | ||
| 60 | 50 | if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL, |
| 61 | 51 | cpu_to_node(cpu))) |
| 62 | 52 | return notifier_from_errno(-ENOMEM); |
| 53 | + cfd->csd = alloc_percpu(struct call_single_data); | |
| 54 | + if (!cfd->csd) { | |
| 55 | + free_cpumask_var(cfd->cpumask); | |
| 56 | + return notifier_from_errno(-ENOMEM); | |
| 57 | + } | |
| 63 | 58 | break; |
| 64 | 59 | |
| 65 | 60 | #ifdef CONFIG_HOTPLUG_CPU |
| @@ -70,6 +65,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) · 4 unmodified lines | ||
| 70 | 65 | case CPU_DEAD_FROZEN: |
| 71 | 66 | free_cpumask_var(cfd->cpumask); |
| 72 | 67 | free_cpumask_var(cfd->cpumask_ipi); |
| 68 | + free_percpu(cfd->csd); | |
| 73 | 69 | break; |
| 74 | 70 | #endif |
| 75 | 71 | }; |
| @@ -170,85 +166,6 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait) · 94 unmodified lines | ||
| 170 | 166 | csd_lock_wait(data); |
| 171 | 167 | } |
| 172 | 168 | |
| 173 | −/* | |
| 174 | − * Invoked by arch to handle an IPI for call function. Must be called with | |
| 175 | − * interrupts disabled. | |
| 176 | − */ | |
| 177 | −void generic_smp_call_function_interrupt(void) | |
| 178 | −{ | |
| 179 | − struct call_function_data *data; | |
| 180 | − int cpu = smp_processor_id(); | |
| 181 | − | |
| 182 | − /* | |
| 183 | − * Shouldn't receive this interrupt on a cpu that is not yet online. | |
| 184 | − */ | |
| 185 | − WARN_ON_ONCE(!cpu_online(cpu)); | |
| 186 | − | |
| 187 | − /* | |
| 188 | − * Ensure entry is visible on call_function_queue after we have | |
| 189 | − * entered the IPI. See comment in smp_call_function_many. | |
| 190 | − * If we don't have this, then we may miss an entry on the list | |
| 191 | − * and never get another IPI to process it. | |
| 192 | − */ | |
| 193 | − smp_mb(); | |
| 194 | − | |
| 195 | − /* | |
| 196 | − * It's ok to use list_for_each_rcu() here even though we may | |
| 197 | − * delete 'pos', since list_del_rcu() doesn't clear ->next | |
| 198 | − */ | |
| 199 | − list_for_each_entry_rcu(data, &call_function.queue, csd.list) { | |
| 200 | − int refs; | |
| 201 | − smp_call_func_t func; | |
| 202 | − | |
| 203 | − /* | |
| 204 | − * Since we walk the list without any locks, we might | |
| 205 | − * see an entry that was completed, removed from the | |
| 206 | − * list and is in the process of being reused. | |
| 207 | − * | |
| 208 | − * We must check that the cpu is in the cpumask before | |
| 209 | − * checking the refs, and both must be set before | |
| 210 | − * executing the callback on this cpu. | |
| 211 | − */ | |
| 212 | − | |
| 213 | − if (!cpumask_test_cpu(cpu, data->cpumask)) | |
| 214 | − continue; | |
| 215 | − | |
| 216 | − smp_rmb(); | |
| 217 | − | |
| 218 | − if (atomic_read(&data->refs) == 0) | |
| 219 | − continue; | |
| 220 | − | |
| 221 | − func = data->csd.func; /* save for later warn */ | |
| 222 | − func(data->csd.info); | |
| 223 | − | |
| 224 | − /* | |
| 225 | − * If the cpu mask is not still set then func enabled | |
| 226 | − * interrupts (BUG), and this cpu took another smp call | |
| 227 | − * function interrupt and executed func(info) twice | |
| 228 | − * on this cpu. That nested execution decremented refs. | |
| 229 | − */ | |
| 230 | − if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) { | |
| 231 | − WARN(1, "%pf enabled interrupts and double executed\n", func); | |
| 232 | − continue; | |
| 233 | − } | |
| 234 | − | |
| 235 | − refs = atomic_dec_return(&data->refs); | |
| 236 | − WARN_ON(refs < 0); | |
| 237 | − | |
| 238 | − if (refs) | |
| 239 | − continue; | |
| 240 | − | |
| 241 | − WARN_ON(!cpumask_empty(data->cpumask)); | |
| 242 | − | |
| 243 | − raw_spin_lock(&call_function.lock); | |
| 244 | − list_del_rcu(&data->csd.list); | |
| 245 | − raw_spin_unlock(&call_function.lock); | |
| 246 | − | |
| 247 | − csd_unlock(&data->csd); | |
| 248 | − } | |
| 249 | − | |
| 250 | −} | |
| 251 | − | |
| 252 | 169 | /* |
| 253 | 170 | * Invoked by arch to handle an IPI for call function single. Must be |
| 254 | 171 | * called from the arch with interrupts disabled. |
| @@ -453,8 +370,7 @@ void smp_call_function_many(const struct cpumask *mask, · 198 unmodified lines | ||
| 453 | 370 | smp_call_func_t func, void *info, bool wait) |
| 454 | 371 | { |
| 455 | 372 | struct call_function_data *data; |
| 456 | − unsigned long flags; | |
| 457 | − int refs, cpu, next_cpu, this_cpu = smp_processor_id(); | |
| 373 | + int cpu, next_cpu, this_cpu = smp_processor_id(); | |
| 458 | 374 | |
| 459 | 375 | /* |
| 460 | 376 | * Can deadlock when called with interrupts disabled. |
| @@ -486,50 +402,13 @@ void smp_call_function_many(const struct cpumask *mask, · 25 unmodified lines | ||
| 486 | 402 | } |
| 487 | 403 | |
| 488 | 404 | data = &__get_cpu_var(cfd_data); |
| 489 | − csd_lock(&data->csd); | |
| 490 | − | |
| 491 | − /* This BUG_ON verifies our reuse assertions and can be removed */ | |
| 492 | − BUG_ON(atomic_read(&data->refs) || !cpumask_empty(data->cpumask)); | |
| 493 | − | |
| 494 | − /* | |
| 495 | − * The global call function queue list add and delete are protected | |
| 496 | − * by a lock, but the list is traversed without any lock, relying | |
| 497 | − * on the rcu list add and delete to allow safe concurrent traversal. | |
| 498 | − * We reuse the call function data without waiting for any grace | |
| 499 | − * period after some other cpu removes it from the global queue. | |
| 500 | − * This means a cpu might find our data block as it is being | |
| 501 | − * filled out. | |
| 502 | − * | |
| 503 | − * We hold off the interrupt handler on the other cpu by | |
| 504 | − * ordering our writes to the cpu mask vs our setting of the | |
| 505 | − * refs counter. We assert only the cpu owning the data block | |
| 506 | − * will set a bit in cpumask, and each bit will only be cleared | |
| 507 | − * by the subject cpu. Each cpu must first find its bit is | |
| 508 | − * set and then check that refs is set indicating the element is | |
| 509 | − * ready to be processed, otherwise it must skip the entry. | |
| 510 | − * | |
| 511 | − * On the previous iteration refs was set to 0 by another cpu. | |
| 512 | − * To avoid the use of transitivity, set the counter to 0 here | |
| 513 | − * so the wmb will pair with the rmb in the interrupt handler. | |
| 514 | − */ | |
| 515 | − atomic_set(&data->refs, 0); /* convert 3rd to 1st party write */ | |
| 516 | − | |
| 517 | − data->csd.func = func; | |
| 518 | − data->csd.info = info; | |
| 519 | 405 | |
| 520 | − /* Ensure 0 refs is visible before mask. Also orders func and info */ | |
| 521 | − smp_wmb(); | |
| 522 | − | |
| 523 | − /* We rely on the "and" being processed before the store */ | |
| 524 | 406 | cpumask_and(data->cpumask, mask, cpu_online_mask); |
| 525 | 407 | cpumask_clear_cpu(this_cpu, data->cpumask); |
| 526 | − refs = cpumask_weight(data->cpumask); | |
| 527 | 408 | |
| 528 | 409 | /* Some callers race with other cpus changing the passed mask */ |
| 529 | − if (unlikely(!refs)) { | |
| 530 | − csd_unlock(&data->csd); | |
| 410 | + if (unlikely(!cpumask_weight(data->cpumask))) | |
| 531 | 411 | return; |
| 532 | − } | |
| 533 | 412 | |
| 534 | 413 | /* |
| 535 | 414 | * After we put an entry into the list, data->cpumask |
| @@ -537,34 +416,32 @@ void smp_call_function_many(const struct cpumask *mask, · 1 unmodified line | ||
| 537 | 416 | * a SMP function call, so data->cpumask will be zero. |
| 538 | 417 | */ |
| 539 | 418 | cpumask_copy(data->cpumask_ipi, data->cpumask); |
| 540 | − raw_spin_lock_irqsave(&call_function.lock, flags); | |
| 541 | − /* | |
| 542 | − * Place entry at the _HEAD_ of the list, so that any cpu still | |
| 543 | − * observing the entry in generic_smp_call_function_interrupt() | |
| 544 | − * will not miss any other list entries: | |
| 545 | − */ | |
| 546 | − list_add_rcu(&data->csd.list, &call_function.queue); | |
| 547 | − /* | |
| 548 | − * We rely on the wmb() in list_add_rcu to complete our writes | |
| 549 | − * to the cpumask before this write to refs, which indicates | |
| 550 | − * data is on the list and is ready to be processed. | |
| 551 | − */ | |
| 552 | − atomic_set(&data->refs, refs); | |
| 553 | − raw_spin_unlock_irqrestore(&call_function.lock, flags); | |
| 554 | 419 | |
| 555 | − /* | |
| 556 | − * Make the list addition visible before sending the ipi. | |
| 557 | − * (IPIs must obey or appear to obey normal Linux cache | |
| 558 | − * coherency rules -- see comment in generic_exec_single). | |
| 559 | − */ | |
| 560 | − smp_mb(); | |
| 420 | + for_each_cpu(cpu, data->cpumask) { | |
| 421 | + struct call_single_data *csd = per_cpu_ptr(data->csd, cpu); | |
| 422 | + struct call_single_queue *dst = | |
| 423 | + &per_cpu(call_single_queue, cpu); | |
| 424 | + unsigned long flags; | |
| 425 | + | |
| 426 | + csd_lock(csd); | |
| 427 | + csd->func = func; | |
| 428 | + csd->info = info; | |
| 429 | + | |
| 430 | + raw_spin_lock_irqsave(&dst->lock, flags); | |
| 431 | + list_add_tail(&csd->list, &dst->list); | |
| 432 | + raw_spin_unlock_irqrestore(&dst->lock, flags); | |
| 433 | + } | |
| 561 | 434 | |
| 562 | 435 | /* Send a message to all CPUs in the map */ |
| 563 | 436 | arch_send_call_function_ipi_mask(data->cpumask_ipi); |
| 564 | 437 | |
| 565 | − /* Optionally wait for the CPUs to complete */ | |
| 566 | − if (wait) | |
| 567 | − csd_lock_wait(&data->csd); | |
| 438 | + if (wait) { | |
| 439 | + for_each_cpu(cpu, data->cpumask) { | |
| 440 | + struct call_single_data *csd = | |
| 441 | + per_cpu_ptr(data->csd, cpu); | |
| 442 | + csd_lock_wait(csd); | |
| 443 | + } | |
| 444 | + } | |
| 568 | 445 | } |
| 569 | 446 | EXPORT_SYMBOL(smp_call_function_many); |
| 570 | 447 | |
| @@ -47,6 +47,7 @@ · 46 unmodified lines | ||
| 47 | 47 | #include <linux/syscalls.h> |
| 48 | 48 | #include <linux/kprobes.h> |
| 49 | 49 | #include <linux/user_namespace.h> |
| 50 | +#include <linux/binfmts.h> | |
| 50 | 51 | |
| 51 | 52 | #include <linux/kmsg_dump.h> |
| 52 | 53 | /* Move somewhere else to avoid recompiling? */ |
| @@ -2012,160 +2013,159 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, · 1959 unmodified lines | ||
| 2012 | 2013 | |
| 2013 | 2014 | error = 0; |
| 2014 | 2015 | switch (option) { |
| 2015 | − case PR_SET_PDEATHSIG: | |
| 2016 | − if (!valid_signal(arg2)) { | |
| 2017 | − error = -EINVAL; | |
| 2018 | − break; | |
| 2019 | − } | |
| 2020 | − me->pdeath_signal = arg2; | |
| 2021 | − break; | |
| 2022 | − case PR_GET_PDEATHSIG: | |
| 2023 | − error = put_user(me->pdeath_signal, (int __user *)arg2); | |
| 2024 | − break; | |
| 2025 | − case PR_GET_DUMPABLE: | |
| 2026 | − error = get_dumpable(me->mm); | |
| 2016 | + case PR_SET_PDEATHSIG: | |
| 2017 | + if (!valid_signal(arg2)) { | |
| 2018 | + error = -EINVAL; | |
| 2027 | 2019 | break; |
| 2028 | − case PR_SET_DUMPABLE: | |
| 2029 | − if (arg2 < 0 || arg2 > 1) { | |
| 2030 | − error = -EINVAL; | |
| 2031 | − break; | |
| 2032 | − } | |
| 2033 | − set_dumpable(me->mm, arg2); | |
| 2020 | + } | |
| 2021 | + me->pdeath_signal = arg2; | |
| 2022 | + break; | |
| 2023 | + case PR_GET_PDEATHSIG: | |
| 2024 | + error = put_user(me->pdeath_signal, (int __user *)arg2); | |
| 2025 | + break; | |
| 2026 | + case PR_GET_DUMPABLE: | |
| 2027 | + error = get_dumpable(me->mm); | |
| 2028 | + break; | |
| 2029 | + case PR_SET_DUMPABLE: | |
| 2030 | + if (arg2 != SUID_DUMP_DISABLE && arg2 != SUID_DUMP_USER) { | |
| 2031 | + error = -EINVAL; | |
| 2034 | 2032 | break; |
| 2033 | + } | |
| 2034 | + set_dumpable(me->mm, arg2); | |
| 2035 | + break; | |
| 2035 | 2036 | |
| 2036 | − case PR_SET_UNALIGN: | |
| 2037 | − error = SET_UNALIGN_CTL(me, arg2); | |
| 2038 | − break; | |
| 2039 | − case PR_GET_UNALIGN: | |
| 2040 | − error = GET_UNALIGN_CTL(me, arg2); | |
| 2041 | − break; | |
| 2042 | − case PR_SET_FPEMU: | |
| 2043 | − error = SET_FPEMU_CTL(me, arg2); | |
| 2044 | − break; | |
| 2045 | − case PR_GET_FPEMU: | |
| 2046 | − error = GET_FPEMU_CTL(me, arg2); | |
| 2047 | − break; | |
| 2048 | − case PR_SET_FPEXC: | |
| 2049 | − error = SET_FPEXC_CTL(me, arg2); | |
| 2050 | − break; | |
| 2051 | − case PR_GET_FPEXC: | |
| 2052 | − error = GET_FPEXC_CTL(me, arg2); | |
| 2053 | − break; | |
| 2054 | − case PR_GET_TIMING: | |
| 2055 | − error = PR_TIMING_STATISTICAL; | |
| 2056 | − break; | |
| 2057 | − case PR_SET_TIMING: | |
| 2058 | − if (arg2 != PR_TIMING_STATISTICAL) | |
| 2059 | − error = -EINVAL; | |
| 2060 | − break; | |
| 2061 | − case PR_SET_NAME: | |
| 2062 | − comm[sizeof(me->comm)-1] = 0; | |
| 2063 | − if (strncpy_from_user(comm, (char __user *)arg2, | |
| 2064 | − sizeof(me->comm) - 1) < 0) | |
| 2065 | − return -EFAULT; | |
| 2066 | − set_task_comm(me, comm); | |
| 2067 | − proc_comm_connector(me); | |
| 2068 | − break; | |
| 2069 | − case PR_GET_NAME: | |
| 2070 | − get_task_comm(comm, me); | |
| 2071 | − if (copy_to_user((char __user *)arg2, comm, | |
| 2072 | − sizeof(comm))) | |
| 2073 | − return -EFAULT; | |
| 2074 | − break; | |
| 2075 | − case PR_GET_ENDIAN: | |
| 2076 | − error = GET_ENDIAN(me, arg2); | |
| 2077 | − break; | |
| 2078 | − case PR_SET_ENDIAN: | |
| 2079 | − error = SET_ENDIAN(me, arg2); | |
| 2080 | − break; | |
| 2081 | − case PR_GET_SECCOMP: | |
| 2082 | − error = prctl_get_seccomp(); | |
| 2083 | − break; | |
| 2084 | − case PR_SET_SECCOMP: | |
| 2085 | − error = prctl_set_seccomp(arg2, (char __user *)arg3); | |
| 2086 | − break; | |
| 2087 | − case PR_GET_TSC: | |
| 2088 | − error = GET_TSC_CTL(arg2); | |
| 2089 | − break; | |
| 2090 | − case PR_SET_TSC: | |
| 2091 | − error = SET_TSC_CTL(arg2); | |
| 2092 | − break; | |
| 2093 | − case PR_TASK_PERF_EVENTS_DISABLE: | |
| 2094 | − error = perf_event_task_disable(); | |
| 2095 | − break; | |
| 2096 | − case PR_TASK_PERF_EVENTS_ENABLE: | |
| 2097 | − error = perf_event_task_enable(); | |
| 2098 | − break; | |
| 2099 | − case PR_GET_TIMERSLACK: | |
| 2100 | − error = current->timer_slack_ns; | |
| 2101 | − break; | |
| 2102 | − case PR_SET_TIMERSLACK: | |
| 2103 | − if (arg2 <= 0) | |
| 2104 | − current->timer_slack_ns = | |
| 2037 | + case PR_SET_UNALIGN: | |
| 2038 | + error = SET_UNALIGN_CTL(me, arg2); | |
| 2039 | + break; | |
| 2040 | + case PR_GET_UNALIGN: | |
| 2041 | + error = GET_UNALIGN_CTL(me, arg2); | |
| 2042 | + break; | |
| 2043 | + case PR_SET_FPEMU: | |
| 2044 | + error = SET_FPEMU_CTL(me, arg2); | |
| 2045 | + break; | |
| 2046 | + case PR_GET_FPEMU: | |
| 2047 | + error = GET_FPEMU_CTL(me, arg2); | |
| 2048 | + break; | |
| 2049 | + case PR_SET_FPEXC: | |
| 2050 | + error = SET_FPEXC_CTL(me, arg2); | |
| 2051 | + break; | |
| 2052 | + case PR_GET_FPEXC: | |
| 2053 | + error = GET_FPEXC_CTL(me, arg2); | |
| 2054 | + break; | |
| 2055 | + case PR_GET_TIMING: | |
| 2056 | + error = PR_TIMING_STATISTICAL; | |
| 2057 | + break; | |
| 2058 | + case PR_SET_TIMING: | |
| 2059 | + if (arg2 != PR_TIMING_STATISTICAL) | |
| 2060 | + error = -EINVAL; | |
| 2061 | + break; | |
| 2062 | + case PR_SET_NAME: | |
| 2063 | + comm[sizeof(me->comm) - 1] = 0; | |
| 2064 | + if (strncpy_from_user(comm, (char __user *)arg2, | |
| 2065 | + sizeof(me->comm) - 1) < 0) | |
| 2066 | + return -EFAULT; | |
| 2067 | + set_task_comm(me, comm); | |
| 2068 | + proc_comm_connector(me); | |
| 2069 | + break; | |
| 2070 | + case PR_GET_NAME: | |
| 2071 | + get_task_comm(comm, me); | |
| 2072 | + if (copy_to_user((char __user *)arg2, comm, sizeof(comm))) | |
| 2073 | + return -EFAULT; | |
| 2074 | + break; | |
| 2075 | + case PR_GET_ENDIAN: | |
| 2076 | + error = GET_ENDIAN(me, arg2); | |
| 2077 | + break; | |
| 2078 | + case PR_SET_ENDIAN: | |
| 2079 | + error = SET_ENDIAN(me, arg2); | |
| 2080 | + break; | |
| 2081 | + case PR_GET_SECCOMP: | |
| 2082 | + error = prctl_get_seccomp(); | |
| 2083 | + break; | |
| 2084 | + case PR_SET_SECCOMP: | |
| 2085 | + error = prctl_set_seccomp(arg2, (char __user *)arg3); | |
| 2086 | + break; | |
| 2087 | + case PR_GET_TSC: | |
| 2088 | + error = GET_TSC_CTL(arg2); | |
| 2089 | + break; | |
| 2090 | + case PR_SET_TSC: | |
| 2091 | + error = SET_TSC_CTL(arg2); | |
| 2092 | + break; | |
| 2093 | + case PR_TASK_PERF_EVENTS_DISABLE: | |
| 2094 | + error = perf_event_task_disable(); | |
| 2095 | + break; | |
| 2096 | + case PR_TASK_PERF_EVENTS_ENABLE: | |
| 2097 | + error = perf_event_task_enable(); | |
| 2098 | + break; | |
| 2099 | + case PR_GET_TIMERSLACK: | |
| 2100 | + error = current->timer_slack_ns; | |
| 2101 | + break; | |
| 2102 | + case PR_SET_TIMERSLACK: | |
| 2103 | + if (arg2 <= 0) | |
| 2104 | + current->timer_slack_ns = | |
| 2105 | 2105 | current->default_timer_slack_ns; |
| 2106 | − else | |
| 2107 | − current->timer_slack_ns = arg2; | |
| 2108 | − break; | |
| 2109 | − case PR_MCE_KILL: | |
| 2110 | − if (arg4 | arg5) | |
| 2111 | − return -EINVAL; | |
| 2112 | − switch (arg2) { | |
| 2113 | − case PR_MCE_KILL_CLEAR: | |
| 2114 | − if (arg3 != 0) | |
| 2115 | − return -EINVAL; | |
| 2116 | − current->flags &= ~PF_MCE_PROCESS; | |
| 2117 | − break; | |
| 2118 | − case PR_MCE_KILL_SET: | |
| 2119 | − current->flags |= PF_MCE_PROCESS; | |
| 2120 | − if (arg3 == PR_MCE_KILL_EARLY) | |
| 2121 | − current->flags |= PF_MCE_EARLY; | |
| 2122 | − else if (arg3 == PR_MCE_KILL_LATE) | |
| 2123 | − current->flags &= ~PF_MCE_EARLY; | |
| 2124 | − else if (arg3 == PR_MCE_KILL_DEFAULT) | |
| 2125 | − current->flags &= | |
| 2126 | − ~(PF_MCE_EARLY|PF_MCE_PROCESS); | |
| 2127 | − else | |
| 2128 | − return -EINVAL; | |
| 2129 | − break; | |
| 2130 | − default: | |
| 2106 | + else | |
| 2107 | + current->timer_slack_ns = arg2; | |
| 2108 | + break; | |
| 2109 | + case PR_MCE_KILL: | |
| 2110 | + if (arg4 | arg5) | |
| 2111 | + return -EINVAL; | |
| 2112 | + switch (arg2) { | |
| 2113 | + case PR_MCE_KILL_CLEAR: | |
| 2114 | + if (arg3 != 0) | |
| 2131 | 2115 | return -EINVAL; |
| 2132 | − } | |
| 2116 | + current->flags &= ~PF_MCE_PROCESS; | |
| 2133 | 2117 | break; |
| 2134 | − case PR_MCE_KILL_GET: | |
| 2135 | − if (arg2 | arg3 | arg4 | arg5) | |
| 2136 | − return -EINVAL; | |
| 2137 | − if (current->flags & PF_MCE_PROCESS) | |
| 2138 | − error = (current->flags & PF_MCE_EARLY) ? | |
| 2139 | − PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE; | |
| 2118 | + case PR_MCE_KILL_SET: | |
| 2119 | + current->flags |= PF_MCE_PROCESS; | |
| 2120 | + if (arg3 == PR_MCE_KILL_EARLY) | |
| 2121 | + current->flags |= PF_MCE_EARLY; | |
| 2122 | + else if (arg3 == PR_MCE_KILL_LATE) | |
| 2123 | + current->flags &= ~PF_MCE_EARLY; | |
| 2124 | + else if (arg3 == PR_MCE_KILL_DEFAULT) | |
| 2125 | + current->flags &= | |
| 2126 | + ~(PF_MCE_EARLY|PF_MCE_PROCESS); | |
| 2140 | 2127 | else |
| 2141 | − error = PR_MCE_KILL_DEFAULT; | |
| 2142 | − break; | |
| 2143 | − case PR_SET_MM: | |
| 2144 | − error = prctl_set_mm(arg2, arg3, arg4, arg5); | |
| 2145 | − break; | |
| 2146 | − case PR_GET_TID_ADDRESS: | |
| 2147 | − error = prctl_get_tid_address(me, (int __user **)arg2); | |
| 2148 | − break; | |
| 2149 | − case PR_SET_CHILD_SUBREAPER: | |
| 2150 | − me->signal->is_child_subreaper = !!arg2; | |
| 2151 | − break; | |
| 2152 | − case PR_GET_CHILD_SUBREAPER: | |
| 2153 | − error = put_user(me->signal->is_child_subreaper, | |
| 2154 | − (int __user *) arg2); | |
| 2155 | − break; | |
| 2156 | − case PR_SET_NO_NEW_PRIVS: | |
| 2157 | − if (arg2 != 1 || arg3 || arg4 || arg5) | |
| 2158 | 2128 | return -EINVAL; |
| 2159 | − | |
| 2160 | − current->no_new_privs = 1; | |
| 2161 | 2129 | break; |
| 2162 | − case PR_GET_NO_NEW_PRIVS: | |
| 2163 | − if (arg2 || arg3 || arg4 || arg5) | |
| 2164 | − return -EINVAL; | |
| 2165 | − return current->no_new_privs ? 1 : 0; | |
| 2166 | 2130 | default: |
| 2167 | − error = -EINVAL; | |
| 2168 | − break; | |
| 2131 | + return -EINVAL; | |
| 2132 | + } | |
| 2133 | + break; | |
| 2134 | + case PR_MCE_KILL_GET: | |
| 2135 | + if (arg2 | arg3 | arg4 | arg5) | |
| 2136 | + return -EINVAL; | |
| 2137 | + if (current->flags & PF_MCE_PROCESS) | |
| 2138 | + error = (current->flags & PF_MCE_EARLY) ? | |
| 2139 | + PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE; | |
| 2140 | + else | |
| 2141 | + error = PR_MCE_KILL_DEFAULT; | |
| 2142 | + break; | |
| 2143 | + case PR_SET_MM: | |
| 2144 | + error = prctl_set_mm(arg2, arg3, arg4, arg5); | |
| 2145 | + break; | |
| 2146 | + case PR_GET_TID_ADDRESS: | |
| 2147 | + error = prctl_get_tid_address(me, (int __user **)arg2); | |
| 2148 | + break; | |
| 2149 | + case PR_SET_CHILD_SUBREAPER: | |
| 2150 | + me->signal->is_child_subreaper = !!arg2; | |
| 2151 | + break; | |
| 2152 | + case PR_GET_CHILD_SUBREAPER: | |
| 2153 | + error = put_user(me->signal->is_child_subreaper, | |
| 2154 | + (int __user *)arg2); | |
| 2155 | + break; | |
| 2156 | + case PR_SET_NO_NEW_PRIVS: | |
| 2157 | + if (arg2 != 1 || arg3 || arg4 || arg5) | |
| 2158 | + return -EINVAL; | |
| 2159 | + | |
| 2160 | + current->no_new_privs = 1; | |
| 2161 | + break; | |
| 2162 | + case PR_GET_NO_NEW_PRIVS: | |
| 2163 | + if (arg2 || arg3 || arg4 || arg5) | |
| 2164 | + return -EINVAL; | |
| 2165 | + return current->no_new_privs ? 1 : 0; | |
| 2166 | + default: | |
| 2167 | + error = -EINVAL; | |
| 2168 | + break; | |
| 2169 | 2169 | } |
| 2170 | 2170 | return error; |
| 2171 | 2171 | } |
| @@ -240,7 +240,7 @@ EXPORT_SYMBOL(current_fs_time); · 239 unmodified lines | ||
| 240 | 240 | * Avoid unnecessary multiplications/divisions in the |
| 241 | 241 | * two most common HZ cases: |
| 242 | 242 | */ |
| 243 | −inline unsigned int jiffies_to_msecs(const unsigned long j) | |
| 243 | +unsigned int jiffies_to_msecs(const unsigned long j) | |
| 244 | 244 | { |
| 245 | 245 | #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) |
| 246 | 246 | return (MSEC_PER_SEC / HZ) * j; |
| @@ -256,7 +256,7 @@ inline unsigned int jiffies_to_msecs(const unsigned long j) · 9 unmodified lines | ||
| 256 | 256 | } |
| 257 | 257 | EXPORT_SYMBOL(jiffies_to_msecs); |
| 258 | 258 | |
| 259 | −inline unsigned int jiffies_to_usecs(const unsigned long j) | |
| 259 | +unsigned int jiffies_to_usecs(const unsigned long j) | |
| 260 | 260 | { |
| 261 | 261 | #if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) |
| 262 | 262 | return (USEC_PER_SEC / HZ) * j; |
| @@ -243,8 +243,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE · 242 unmodified lines | ||
| 243 | 243 | default 1 if BOOTPARAM_SOFTLOCKUP_PANIC |
| 244 | 244 | |
| 245 | 245 | config PANIC_ON_OOPS |
| 246 | − bool "Panic on Oops" if EXPERT | |
| 247 | − default n | |
| 246 | + bool "Panic on Oops" | |
| 248 | 247 | help |
| 249 | 248 | Say Y here to enable the kernel to panic when it oopses. This |
| 250 | 249 | has the same effect as setting oops=panic on the kernel command |
| @@ -157,7 +157,7 @@ static int match_number(substring_t *s, int *result, int base) · 156 unmodified lines | ||
| 157 | 157 | * |
| 158 | 158 | * Description: Attempts to parse the &substring_t @s as a decimal integer. On |
| 159 | 159 | * success, sets @result to the integer represented by the string and returns 0. |
| 160 | − * Returns either -ENOMEM or -EINVAL on failure. | |
| 160 | + * Returns -ENOMEM, -EINVAL, or -ERANGE on failure. | |
| 161 | 161 | */ |
| 162 | 162 | int match_int(substring_t *s, int *result) |
| 163 | 163 | { |
| @@ -171,7 +171,7 @@ int match_int(substring_t *s, int *result) · 7 unmodified lines | ||
| 171 | 171 | * |
| 172 | 172 | * Description: Attempts to parse the &substring_t @s as an octal integer. On |
| 173 | 173 | * success, sets @result to the integer represented by the string and returns |
| 174 | − * 0. Returns either -ENOMEM or -EINVAL on failure. | |
| 174 | + * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. | |
| 175 | 175 | */ |
| 176 | 176 | int match_octal(substring_t *s, int *result) |
| 177 | 177 | { |
| @@ -185,7 +185,7 @@ int match_octal(substring_t *s, int *result) · 7 unmodified lines | ||
| 185 | 185 | * |
| 186 | 186 | * Description: Attempts to parse the &substring_t @s as a hexadecimal integer. |
| 187 | 187 | * On success, sets @result to the integer represented by the string and |
| 188 | − * returns 0. Returns either -ENOMEM or -EINVAL on failure. | |
| 188 | + * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. | |
| 189 | 189 | */ |
| 190 | 190 | int match_hex(substring_t *s, int *result) |
| 191 | 191 | { |
| @@ -1030,6 +1030,7 @@ int kptr_restrict __read_mostly; · 1029 unmodified lines | ||
| 1030 | 1030 | * N no separator |
| 1031 | 1031 | * The maximum supported length is 64 bytes of the input. Consider |
| 1032 | 1032 | * to use print_hex_dump() for the larger input. |
| 1033 | + * - 'a' For a phys_addr_t type and its derivative types (passed by reference) | |
| 1033 | 1034 | * |
| 1034 | 1035 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 |
| 1035 | 1036 | * function pointers are really function descriptors, which contain a |
| @@ -1120,6 +1121,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, · 84 unmodified lines | ||
| 1120 | 1121 | return netdev_feature_string(buf, end, ptr, spec); |
| 1121 | 1122 | } |
| 1122 | 1123 | break; |
| 1124 | + case 'a': | |
| 1125 | + spec.flags |= SPECIAL | SMALL | ZEROPAD; | |
| 1126 | + spec.field_width = sizeof(phys_addr_t) * 2 + 2; | |
| 1127 | + spec.base = 16; | |
| 1128 | + return number(buf, end, | |
| 1129 | + (unsigned long long) *((phys_addr_t *)ptr), spec); | |
| 1123 | 1130 | } |
| 1124 | 1131 | spec.flags |= SMALL; |
| 1125 | 1132 | if (spec.field_width == -1) { |
| @@ -6,42 +6,40 @@ config XZ_DEC · 5 unmodified lines | ||
| 6 | 6 | the .xz file format as the container. For integrity checking, |
| 7 | 7 | CRC32 is supported. See Documentation/xz.txt for more information. |
| 8 | 8 | |
| 9 | +if XZ_DEC | |
| 10 | + | |
| 9 | 11 | config XZ_DEC_X86 |
| 10 | − bool "x86 BCJ filter decoder" if EXPERT | |
| 11 | − default y | |
| 12 | − depends on XZ_DEC | |
| 12 | + bool "x86 BCJ filter decoder" | |
| 13 | + default y if X86 | |
| 13 | 14 | select XZ_DEC_BCJ |
| 14 | 15 | |
| 15 | 16 | config XZ_DEC_POWERPC |
| 16 | − bool "PowerPC BCJ filter decoder" if EXPERT | |
| 17 | − default y | |
| 18 | − depends on XZ_DEC | |
| 17 | + bool "PowerPC BCJ filter decoder" | |
| 18 | + default y if POWERPC | |
| 19 | 19 | select XZ_DEC_BCJ |
| 20 | 20 | |
| 21 | 21 | config XZ_DEC_IA64 |
| 22 | − bool "IA-64 BCJ filter decoder" if EXPERT | |
| 23 | − default y | |
| 24 | − depends on XZ_DEC | |
| 22 | + bool "IA-64 BCJ filter decoder" | |
| 23 | + default y if IA64 | |
| 25 | 24 | select XZ_DEC_BCJ |
| 26 | 25 | |
| 27 | 26 | config XZ_DEC_ARM |
| 28 | − bool "ARM BCJ filter decoder" if EXPERT | |
| 29 | − default y | |
| 30 | − depends on XZ_DEC | |
| 27 | + bool "ARM BCJ filter decoder" | |
| 28 | + default y if ARM | |
| 31 | 29 | select XZ_DEC_BCJ |
| 32 | 30 | |
| 33 | 31 | config XZ_DEC_ARMTHUMB |
| 34 | − bool "ARM-Thumb BCJ filter decoder" if EXPERT | |
| 35 | − default y | |
| 36 | − depends on XZ_DEC | |
| 32 | + bool "ARM-Thumb BCJ filter decoder" | |
| 33 | + default y if (ARM && ARM_THUMB) | |
| 37 | 34 | select XZ_DEC_BCJ |
| 38 | 35 | |
| 39 | 36 | config XZ_DEC_SPARC |
| 40 | − bool "SPARC BCJ filter decoder" if EXPERT | |
| 41 | − default y | |
| 42 | − depends on XZ_DEC | |
| 37 | + bool "SPARC BCJ filter decoder" | |
| 38 | + default y if SPARC | |
| 43 | 39 | select XZ_DEC_BCJ |
| 44 | 40 | |
| 41 | +endif | |
| 42 | + | |
| 45 | 43 | config XZ_DEC_BCJ |
| 46 | 44 | bool |
| 47 | 45 | default n |
| @@ -258,6 +258,19 @@ config BOUNCE · 257 unmodified lines | ||
| 258 | 258 | def_bool y |
| 259 | 259 | depends on BLOCK && MMU && (ZONE_DMA || HIGHMEM) |
| 260 | 260 | |
| 261 | +# On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often | |
| 262 | +# have more than 4GB of memory, but we don't currently use the IOTLB to present | |
| 263 | +# a 32-bit address to OHCI. So we need to use a bounce pool instead. | |
| 264 | +# | |
| 265 | +# We also use the bounce pool to provide stable page writes for jbd. jbd | |
| 266 | +# initiates buffer writeback without locking the page or setting PG_writeback, | |
| 267 | +# and fixing that behavior (a second time; jbd2 doesn't have this problem) is | |
| 268 | +# a major rework effort. Instead, use the bounce buffer to snapshot pages | |
| 269 | +# (until jbd goes away). The only jbd user is ext3. | |
| 270 | +config NEED_BOUNCE_POOL | |
| 271 | + bool | |
| 272 | + default y if (TILE && USB_OHCI_HCD) || (BLK_DEV_INTEGRITY && JBD) | |
| 273 | + | |
| 261 | 274 | config NR_QUICK |
| 262 | 275 | int |
| 263 | 276 | depends on QUICKLIST |
| @@ -221,12 +221,23 @@ static ssize_t max_ratio_store(struct device *dev, · 220 unmodified lines | ||
| 221 | 221 | } |
| 222 | 222 | BDI_SHOW(max_ratio, bdi->max_ratio) |
| 223 | 223 | |
| 224 | +static ssize_t stable_pages_required_show(struct device *dev, | |
| 225 | + struct device_attribute *attr, | |
| 226 | + char *page) | |
| 227 | +{ | |
| 228 | + struct backing_dev_info *bdi = dev_get_drvdata(dev); | |
| 229 | + | |
| 230 | + return snprintf(page, PAGE_SIZE-1, "%d\n", | |
| 231 | + bdi_cap_stable_pages_required(bdi) ? 1 : 0); | |
| 232 | +} | |
| 233 | + | |
| 224 | 234 | #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store) |
| 225 | 235 | |
| 226 | 236 | static struct device_attribute bdi_dev_attrs[] = { |
| 227 | 237 | __ATTR_RW(read_ahead_kb), |
| 228 | 238 | __ATTR_RW(min_ratio), |
| 229 | 239 | __ATTR_RW(max_ratio), |
| 240 | + __ATTR_RO(stable_pages_required), | |
| 230 | 241 | __ATTR_NULL, |
| 231 | 242 | }; |
| 232 | 243 | |
| @@ -178,8 +178,45 @@ static void bounce_end_io_read_isa(struct bio *bio, int err) · 177 unmodified lines | ||
| 178 | 178 | __bounce_end_io_read(bio, isa_page_pool, err); |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | +#ifdef CONFIG_NEED_BOUNCE_POOL | |
| 182 | +static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) | |
| 183 | +{ | |
| 184 | + struct page *page; | |
| 185 | + struct backing_dev_info *bdi; | |
| 186 | + struct address_space *mapping; | |
| 187 | + struct bio_vec *from; | |
| 188 | + int i; | |
| 189 | + | |
| 190 | + if (bio_data_dir(bio) != WRITE) | |
| 191 | + return 0; | |
| 192 | + | |
| 193 | + if (!bdi_cap_stable_pages_required(&q->backing_dev_info)) | |
| 194 | + return 0; | |
| 195 | + | |
| 196 | + /* | |
| 197 | + * Based on the first page that has a valid mapping, decide whether or | |
| 198 | + * not we have to employ bounce buffering to guarantee stable pages. | |
| 199 | + */ | |
| 200 | + bio_for_each_segment(from, bio, i) { | |
| 201 | + page = from->bv_page; | |
| 202 | + mapping = page_mapping(page); | |
| 203 | + if (!mapping) | |
| 204 | + continue; | |
| 205 | + bdi = mapping->backing_dev_info; | |
| 206 | + return mapping->host->i_sb->s_flags & MS_SNAP_STABLE; | |
| 207 | + } | |
| 208 | + | |
| 209 | + return 0; | |
| 210 | +} | |
| 211 | +#else | |
| 212 | +static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) | |
| 213 | +{ | |
| 214 | + return 0; | |
| 215 | +} | |
| 216 | +#endif /* CONFIG_NEED_BOUNCE_POOL */ | |
| 217 | + | |
| 181 | 218 | static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, |
| 182 | − mempool_t *pool) | |
| 219 | + mempool_t *pool, int force) | |
| 183 | 220 | { |
| 184 | 221 | struct page *page; |
| 185 | 222 | struct bio *bio = NULL; |
| @@ -192,7 +229,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, · 6 unmodified lines | ||
| 192 | 229 | /* |
| 193 | 230 | * is destination page below bounce pfn? |
| 194 | 231 | */ |
| 195 | − if (page_to_pfn(page) <= queue_bounce_pfn(q)) | |
| 232 | + if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force) | |
| 196 | 233 | continue; |
| 197 | 234 | |
| 198 | 235 | /* |
| @@ -270,6 +307,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, · 71 unmodified lines | ||
| 270 | 307 | |
| 271 | 308 | void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) |
| 272 | 309 | { |
| 310 | + int must_bounce; | |
| 273 | 311 | mempool_t *pool; |
| 274 | 312 | |
| 275 | 313 | /* |
| @@ -278,13 +316,15 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) · 2 unmodified lines | ||
| 278 | 316 | if (!bio_has_data(*bio_orig)) |
| 279 | 317 | return; |
| 280 | 318 | |
| 319 | + must_bounce = must_snapshot_stable_pages(q, *bio_orig); | |
| 320 | + | |
| 281 | 321 | /* |
| 282 | 322 | * for non-isa bounce case, just check if the bounce pfn is equal |
| 283 | 323 | * to or bigger than the highest pfn in the system -- in that case, |
| 284 | 324 | * don't waste time iterating over bio segments |
| 285 | 325 | */ |
| 286 | 326 | if (!(q->bounce_gfp & GFP_DMA)) { |
| 287 | − if (queue_bounce_pfn(q) >= blk_max_pfn) | |
| 327 | + if (queue_bounce_pfn(q) >= blk_max_pfn && !must_bounce) | |
| 288 | 328 | return; |
| 289 | 329 | pool = page_pool; |
| 290 | 330 | } else { |
| @@ -295,7 +335,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) · 4 unmodified lines | ||
| 295 | 335 | /* |
| 296 | 336 | * slow path |
| 297 | 337 | */ |
| 298 | − __blk_queue_bounce(q, bio_orig, pool); | |
| 338 | + __blk_queue_bounce(q, bio_orig, pool, must_bounce); | |
| 299 | 339 | } |
| 300 | 340 | |
| 301 | 341 | EXPORT_SYMBOL(blk_queue_bounce); |
| @@ -1728,6 +1728,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) · 1727 unmodified lines | ||
| 1728 | 1728 | * see the dirty page and writeprotect it again. |
| 1729 | 1729 | */ |
| 1730 | 1730 | set_page_dirty(page); |
| 1731 | + wait_for_stable_page(page); | |
| 1731 | 1732 | out: |
| 1732 | 1733 | sb_end_pagefault(inode->i_sb); |
| 1733 | 1734 | return ret; |
| @@ -2274,7 +2275,7 @@ repeat: · 540 unmodified lines | ||
| 2274 | 2275 | return NULL; |
| 2275 | 2276 | } |
| 2276 | 2277 | found: |
| 2277 | − wait_on_page_writeback(page); | |
| 2278 | + wait_for_stable_page(page); | |
| 2278 | 2279 | return page; |
| 2279 | 2280 | } |
| 2280 | 2281 | EXPORT_SYMBOL(grab_cache_page_write_begin); |
| @@ -2290,3 +2290,27 @@ int mapping_tagged(struct address_space *mapping, int tag) · 2289 unmodified lines | ||
| 2290 | 2290 | return radix_tree_tagged(&mapping->page_tree, tag); |
| 2291 | 2291 | } |
| 2292 | 2292 | EXPORT_SYMBOL(mapping_tagged); |
| 2293 | + | |
| 2294 | +/** | |
| 2295 | + * wait_for_stable_page() - wait for writeback to finish, if necessary. | |
| 2296 | + * @page: The page to wait on. | |
| 2297 | + * | |
| 2298 | + * This function determines if the given page is related to a backing device | |
| 2299 | + * that requires page contents to be held stable during writeback. If so, then | |
| 2300 | + * it will wait for any pending writeback to complete. | |
| 2301 | + */ | |
| 2302 | +void wait_for_stable_page(struct page *page) | |
| 2303 | +{ | |
| 2304 | + struct address_space *mapping = page_mapping(page); | |
| 2305 | + struct backing_dev_info *bdi = mapping->backing_dev_info; | |
| 2306 | + | |
| 2307 | + if (!bdi_cap_stable_pages_required(bdi)) | |
| 2308 | + return; | |
| 2309 | +#ifdef CONFIG_NEED_BOUNCE_POOL | |
| 2310 | + if (mapping->host->i_sb->s_flags & MS_SNAP_STABLE) | |
| 2311 | + return; | |
| 2312 | +#endif /* CONFIG_NEED_BOUNCE_POOL */ | |
| 2313 | + | |
| 2314 | + wait_on_page_writeback(page); | |
| 2315 | +} | |
| 2316 | +EXPORT_SYMBOL_GPL(wait_for_stable_page); | |
| @@ -11,7 +11,7 @@ menuconfig IPV6 · 10 unmodified lines | ||
| 11 | 11 | You will still be able to do traditional IPv4 networking as well. |
| 12 | 12 | |
| 13 | 13 | For general information about IPv6, see |
| 14 | − <http://playground.sun.com/pub/ipng/html/ipng-main.html>. | |
| 14 | + <https://en.wikipedia.org/wiki/IPv6>. | |
| 15 | 15 | For Linux IPv6 development information, see <http://www.linux-ipv6.org>. |
| 16 | 16 | For specific information about IPv6 under Linux, read the HOWTO at |
| 17 | 17 | <http://www.bieringer.de/linux/IPv6/>. |
| @@ -1931,6 +1931,12 @@ sub process { · 1930 unmodified lines | ||
| 1931 | 1931 | "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); |
| 1932 | 1932 | } |
| 1933 | 1933 | |
| 1934 | +# check for old HOTPLUG __dev<foo> section markings | |
| 1935 | + if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { | |
| 1936 | + WARN("HOTPLUG_SECTION", | |
| 1937 | + "Using $1 is unnecessary\n" . $herecurr); | |
| 1938 | + } | |
| 1939 | + | |
| 1934 | 1940 | # Check for potential 'bare' types |
| 1935 | 1941 | my ($stat, $cond, $line_nr_next, $remain_next, $off_next, |
| 1936 | 1942 | $realline_next); |
| @@ -2430,6 +2436,15 @@ sub process { · 493 unmodified lines | ||
| 2430 | 2436 | "Prefer pr_warn(... to pr_warning(...\n" . $herecurr); |
| 2431 | 2437 | } |
| 2432 | 2438 | |
| 2439 | + if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { | |
| 2440 | + my $orig = $1; | |
| 2441 | + my $level = lc($orig); | |
| 2442 | + $level = "warn" if ($level eq "warning"); | |
| 2443 | + $level = "dbg" if ($level eq "debug"); | |
| 2444 | + WARN("PREFER_DEV_LEVEL", | |
| 2445 | + "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); | |
| 2446 | + } | |
| 2447 | + | |
| 2433 | 2448 | # function brace can't be on same line, except for #defines of do while, |
| 2434 | 2449 | # or if closed on same line |
| 2435 | 2450 | if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and |
| @@ -2915,6 +2930,7 @@ sub process { · 479 unmodified lines | ||
| 2915 | 2930 | my $var = $1; |
| 2916 | 2931 | if ($var !~ /$Constant/ && |
| 2917 | 2932 | $var =~ /[A-Z]\w*[a-z]|[a-z]\w*[A-Z]/ && |
| 2933 | + $var !~ /^Page[A-Z]/ && | |
| 2918 | 2934 | !defined $camelcase{$var}) { |
| 2919 | 2935 | $camelcase{$var} = 1; |
| 2920 | 2936 | WARN("CAMELCASE", |
| @@ -3237,9 +3253,9 @@ sub process { · 316 unmodified lines | ||
| 3237 | 3253 | } |
| 3238 | 3254 | |
| 3239 | 3255 | # prefer usleep_range over udelay |
| 3240 | − if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) { | |
| 3256 | + if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { | |
| 3241 | 3257 | # ignore udelay's < 10, however |
| 3242 | − if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) { | |
| 3258 | + if (! ($1 < 10) ) { | |
| 3243 | 3259 | CHK("USLEEP_RANGE", |
| 3244 | 3260 | "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line); |
| 3245 | 3261 | } |
| @@ -3460,6 +3476,12 @@ sub process { · 214 unmodified lines | ||
| 3460 | 3476 | "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); |
| 3461 | 3477 | } |
| 3462 | 3478 | |
| 3479 | +# check for alloc argument mismatch | |
| 3480 | + if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) { | |
| 3481 | + WARN("ALLOC_ARRAY_ARGS", | |
| 3482 | + "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); | |
| 3483 | + } | |
| 3484 | + | |
| 3463 | 3485 | # check for multiple semicolons |
| 3464 | 3486 | if ($line =~ /;\s*;\s*$/) { |
| 3465 | 3487 | WARN("ONE_SEMICOLON", |
| @@ -433,7 +433,7 @@ foreach my $file (@ARGV) { · 432 unmodified lines | ||
| 433 | 433 | |
| 434 | 434 | while (<$patch>) { |
| 435 | 435 | my $patch_line = $_; |
| 436 | − if (m/^\+\+\+\s+(\S+)/) { | |
| 436 | + if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { | |
| 437 | 437 | my $filename = $1; |
| 438 | 438 | $filename =~ s@^[^/]*/@@; |
| 439 | 439 | $filename =~ s@\n@@; |
| @@ -149,12 +149,17 @@ dogtags() · 148 unmodified lines | ||
| 149 | 149 | exuberant() |
| 150 | 150 | { |
| 151 | 151 | all_target_sources | xargs $1 -a \ |
| 152 | − -I __initdata,__exitdata,__acquires,__releases \ | |
| 153 | − -I __read_mostly,____cacheline_aligned \ | |
| 152 | + -I __initdata,__exitdata,__initconst,__devinitdata \ | |
| 153 | + -I __devinitconst,__cpuinitdata,__initdata_memblock \ | |
| 154 | + -I __refdata,__attribute \ | |
| 155 | + -I __acquires,__releases,__deprecated \ | |
| 156 | + -I __read_mostly,__aligned,____cacheline_aligned \ | |
| 154 | 157 | -I ____cacheline_aligned_in_smp \ |
| 155 | 158 | -I ____cacheline_internodealigned_in_smp \ |
| 159 | + -I __used,__packed,__packed2__,__must_check,__must_hold \ | |
| 156 | 160 | -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ |
| 157 | 161 | -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ |
| 162 | + -I static,const \ | |
| 158 | 163 | --extra=+f --c-kinds=+px \ |
| 159 | 164 | --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \ |
| 160 | 165 | --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ |
| @@ -182,8 +187,19 @@ exuberant() · 21 unmodified lines | ||
| 182 | 187 | --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ |
| 183 | 188 | --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ |
| 184 | 189 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ |
| 185 | − --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ | |
| 186 | − --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' | |
| 190 | + --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \ | |
| 191 | + --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \ | |
| 192 | + --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \ | |
| 193 | + --regex-c='/DEFINE_(RAW_SPINLOCK|RWLOCK|SEQLOCK)\((\w*)/\2/v/' \ | |
| 194 | + --regex-c='/DECLARE_(RWSEM|COMPLETION)\((\w*)/\2/v/' \ | |
| 195 | + --regex-c='/DECLARE_BITMAP\((\w*)/\1/v/' \ | |
| 196 | + --regex-c='/(^|\s)(|L|H)LIST_HEAD\((\w*)/\3/v/' \ | |
| 197 | + --regex-c='/(^|\s)RADIX_TREE\((\w*)/\2/v/' \ | |
| 198 | + --regex-c='/DEFINE_PER_CPU\(([^,]*,\s*)(\w*).*\)/\2/v/' \ | |
| 199 | + --regex-c='/DEFINE_PER_CPU_SHARED_ALIGNED\(([^,]*,\s*)(\w*).*\)/\2/v/' \ | |
| 200 | + --regex-c='/DECLARE_WAIT_QUEUE_HEAD\((\w*)/\1/v/' \ | |
| 201 | + --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/' \ | |
| 202 | + --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/' | |
| 187 | 203 | |
| 188 | 204 | all_kconfigs | xargs $1 -a \ |
| 189 | 205 | --langdef=kconfig --language-force=kconfig \ |
| @@ -159,6 +159,16 @@ static void dev_exception_rm(struct dev_cgroup *dev_cgroup, · 158 unmodified lines | ||
| 159 | 159 | } |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | +static void __dev_exception_clean(struct dev_cgroup *dev_cgroup) | |
| 163 | +{ | |
| 164 | + struct dev_exception_item *ex, *tmp; | |
| 165 | + | |
| 166 | + list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { | |
| 167 | + list_del_rcu(&ex->list); | |
| 168 | + kfree_rcu(ex, rcu); | |
| 169 | + } | |
| 170 | +} | |
| 171 | + | |
| 162 | 172 | /** |
| 163 | 173 | * dev_exception_clean - frees all entries of the exception list |
| 164 | 174 | * @dev_cgroup: dev_cgroup with the exception list to be cleaned |
| @@ -167,14 +177,9 @@ static void dev_exception_rm(struct dev_cgroup *dev_cgroup, · 2 unmodified lines | ||
| 167 | 177 | */ |
| 168 | 178 | static void dev_exception_clean(struct dev_cgroup *dev_cgroup) |
| 169 | 179 | { |
| 170 | − struct dev_exception_item *ex, *tmp; | |
| 171 | − | |
| 172 | 180 | lockdep_assert_held(&devcgroup_mutex); |
| 173 | 181 | |
| 174 | − list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { | |
| 175 | − list_del_rcu(&ex->list); | |
| 176 | − kfree_rcu(ex, rcu); | |
| 177 | − } | |
| 182 | + __dev_exception_clean(dev_cgroup); | |
| 178 | 183 | } |
| 179 | 184 | |
| 180 | 185 | /* |
| @@ -215,9 +220,7 @@ static void devcgroup_css_free(struct cgroup *cgroup) · 34 unmodified lines | ||
| 215 | 220 | struct dev_cgroup *dev_cgroup; |
| 216 | 221 | |
| 217 | 222 | dev_cgroup = cgroup_to_devcgroup(cgroup); |
| 218 | − mutex_lock(&devcgroup_mutex); | |
| 219 | − dev_exception_clean(dev_cgroup); | |
| 220 | − mutex_unlock(&devcgroup_mutex); | |
| 223 | + __dev_exception_clean(dev_cgroup); | |
| 221 | 224 | kfree(dev_cgroup); |
| 222 | 225 | } |
| 223 | 226 | |