Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'staging-4.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging and IIO driver fixes from Greg KH:
"Here are some IIO driver fixes, along with two staging driver fixes
for 4.6-rc3.

One staging driver patch reverts the deletion of a driver that
happened in 4.6-rc1. We thought that laptop.org was dead, but it's
still alive and kicking, and has users that were mad we broke their
hardware by deleting a driver for their machines. So that driver is
added back and everyone is happy again.

All of these have been in linux-next for a while with no reported
issues"

* tag 'staging-4.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging:
Revert "Staging: olpc_dcon: Remove obsolete driver"
staging/rdma/hfi1: select CRC32
iio: gyro: bmg160: fix buffer read values
iio: gyro: bmg160: fix endianness when reading axes
iio: accel: bmc150: fix endianness when reading axes
iio: st_magn: always define ST_MAGN_TRIGGER_SET_STATE
iio: fix config watermark initial value
iio: health: max30100: correct FIFO check condition
iio: imu: Fix inv_mpu6050 dependencies
iio: adc: Fix build error of missing devm_ioremap_resource on UM
iio: light: apds9960: correct FIFO check condition
iio: adc: max1363: correct reference voltage
iio: adc: max1363: add missing adc to max1363_id

+1377 -15
+8
MAINTAINERS
··· 10595 10595 S: Maintained 10596 10596 F: drivers/staging/nvec/ 10597 10597 10598 + STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON) 10599 + M: Jens Frederich <jfrederich@gmail.com> 10600 + M: Daniel Drake <dsd@laptop.org> 10601 + M: Jon Nettleton <jon.nettleton@gmail.com> 10602 + W: http://wiki.laptop.org/go/DCON 10603 + S: Maintained 10604 + F: drivers/staging/olpc_dcon/ 10605 + 10598 10606 STAGING - REALTEK RTL8712U DRIVERS 10599 10607 M: Larry Finger <Larry.Finger@lwfinger.net> 10600 10608 M: Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
+4 -3
drivers/iio/accel/bmc150-accel-core.c
··· 547 547 { 548 548 int ret; 549 549 int axis = chan->scan_index; 550 - unsigned int raw_val; 550 + __le16 raw_val; 551 551 552 552 mutex_lock(&data->mutex); 553 553 ret = bmc150_accel_set_power_state(data, true); ··· 557 557 } 558 558 559 559 ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis), 560 - &raw_val, 2); 560 + &raw_val, sizeof(raw_val)); 561 561 if (ret < 0) { 562 562 dev_err(data->dev, "Error reading axis %d\n", axis); 563 563 bmc150_accel_set_power_state(data, false); 564 564 mutex_unlock(&data->mutex); 565 565 return ret; 566 566 } 567 - *val = sign_extend32(raw_val >> chan->scan_type.shift, 567 + *val = sign_extend32(le16_to_cpu(raw_val) >> chan->scan_type.shift, 568 568 chan->scan_type.realbits - 1); 569 569 ret = bmc150_accel_set_power_state(data, false); 570 570 mutex_unlock(&data->mutex); ··· 988 988 .realbits = (bits), \ 989 989 .storagebits = 16, \ 990 990 .shift = 16 - (bits), \ 991 + .endianness = IIO_LE, \ 991 992 }, \ 992 993 .event_spec = &bmc150_accel_event, \ 993 994 .num_event_specs = 1 \
+1
drivers/iio/adc/Kconfig
··· 134 134 config AT91_SAMA5D2_ADC 135 135 tristate "Atmel AT91 SAMA5D2 ADC" 136 136 depends on ARCH_AT91 || COMPILE_TEST 137 + depends on HAS_IOMEM 137 138 help 138 139 Say yes here to build support for Atmel SAMA5D2 ADC which is 139 140 available on SAMA5D2 SoC family.
+8 -4
drivers/iio/adc/max1363.c
··· 1386 1386 }, 1387 1387 [max11644] = { 1388 1388 .bits = 12, 1389 - .int_vref_mv = 2048, 1389 + .int_vref_mv = 4096, 1390 1390 .mode_list = max11644_mode_list, 1391 1391 .num_modes = ARRAY_SIZE(max11644_mode_list), 1392 1392 .default_mode = s0to1, ··· 1396 1396 }, 1397 1397 [max11645] = { 1398 1398 .bits = 12, 1399 - .int_vref_mv = 4096, 1399 + .int_vref_mv = 2048, 1400 1400 .mode_list = max11644_mode_list, 1401 1401 .num_modes = ARRAY_SIZE(max11644_mode_list), 1402 1402 .default_mode = s0to1, ··· 1406 1406 }, 1407 1407 [max11646] = { 1408 1408 .bits = 10, 1409 - .int_vref_mv = 2048, 1409 + .int_vref_mv = 4096, 1410 1410 .mode_list = max11644_mode_list, 1411 1411 .num_modes = ARRAY_SIZE(max11644_mode_list), 1412 1412 .default_mode = s0to1, ··· 1416 1416 }, 1417 1417 [max11647] = { 1418 1418 .bits = 10, 1419 - .int_vref_mv = 4096, 1419 + .int_vref_mv = 2048, 1420 1420 .mode_list = max11644_mode_list, 1421 1421 .num_modes = ARRAY_SIZE(max11644_mode_list), 1422 1422 .default_mode = s0to1, ··· 1680 1680 { "max11615", max11615 }, 1681 1681 { "max11616", max11616 }, 1682 1682 { "max11617", max11617 }, 1683 + { "max11644", max11644 }, 1684 + { "max11645", max11645 }, 1685 + { "max11646", max11646 }, 1686 + { "max11647", max11647 }, 1683 1687 {} 1684 1688 }; 1685 1689
+5 -4
drivers/iio/gyro/bmg160_core.c
··· 452 452 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val) 453 453 { 454 454 int ret; 455 - unsigned int raw_val; 455 + __le16 raw_val; 456 456 457 457 mutex_lock(&data->mutex); 458 458 ret = bmg160_set_power_state(data, true); ··· 462 462 } 463 463 464 464 ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val, 465 - 2); 465 + sizeof(raw_val)); 466 466 if (ret < 0) { 467 467 dev_err(data->dev, "Error reading axis %d\n", axis); 468 468 bmg160_set_power_state(data, false); ··· 470 470 return ret; 471 471 } 472 472 473 - *val = sign_extend32(raw_val, 15); 473 + *val = sign_extend32(le16_to_cpu(raw_val), 15); 474 474 ret = bmg160_set_power_state(data, false); 475 475 mutex_unlock(&data->mutex); 476 476 if (ret < 0) ··· 733 733 .sign = 's', \ 734 734 .realbits = 16, \ 735 735 .storagebits = 16, \ 736 + .endianness = IIO_LE, \ 736 737 }, \ 737 738 .event_spec = &bmg160_event, \ 738 739 .num_event_specs = 1 \ ··· 781 780 mutex_unlock(&data->mutex); 782 781 goto err; 783 782 } 784 - data->buffer[i++] = ret; 783 + data->buffer[i++] = val; 785 784 } 786 785 mutex_unlock(&data->mutex); 787 786
+2 -1
drivers/iio/health/max30100.c
··· 238 238 239 239 mutex_lock(&data->lock); 240 240 241 - while (cnt-- || (cnt = max30100_fifo_count(data) > 0)) { 241 + while (cnt || (cnt = max30100_fifo_count(data) > 0)) { 242 242 ret = max30100_read_measurement(data); 243 243 if (ret) 244 244 break; 245 245 246 246 iio_push_to_buffers(data->indio_dev, data->buffer); 247 + cnt--; 247 248 } 248 249 249 250 mutex_unlock(&data->lock);
+1 -2
drivers/iio/imu/inv_mpu6050/Kconfig
··· 9 9 10 10 config INV_MPU6050_I2C 11 11 tristate "Invensense MPU6050 devices (I2C)" 12 - depends on I2C 12 + depends on I2C_MUX 13 13 select INV_MPU6050_IIO 14 - select I2C_MUX 15 14 select REGMAP_I2C 16 15 help 17 16 This driver supports the Invensense MPU6050 devices.
+1
drivers/iio/industrialio-buffer.c
··· 653 653 unsigned int modes; 654 654 655 655 memset(config, 0, sizeof(*config)); 656 + config->watermark = ~0; 656 657 657 658 /* 658 659 * If there is just one buffer and we are removing it there is nothing
+2 -1
drivers/iio/light/apds9960.c
··· 769 769 mutex_lock(&data->lock); 770 770 data->gesture_mode_running = 1; 771 771 772 - while (cnt-- || (cnt = apds9660_fifo_is_empty(data) > 0)) { 772 + while (cnt || (cnt = apds9660_fifo_is_empty(data) > 0)) { 773 773 ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE, 774 774 &data->buffer, 4); 775 775 ··· 777 777 goto err_read; 778 778 779 779 iio_push_to_buffers(data->indio_dev, data->buffer); 780 + cnt--; 780 781 } 781 782 782 783 err_read:
+1
drivers/iio/magnetometer/st_magn.h
··· 44 44 static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev) 45 45 { 46 46 } 47 + #define ST_MAGN_TRIGGER_SET_STATE NULL 47 48 #endif /* CONFIG_IIO_BUFFER */ 48 49 49 50 #endif /* ST_MAGN_H */
+2
drivers/staging/Kconfig
··· 30 30 31 31 source "drivers/staging/comedi/Kconfig" 32 32 33 + source "drivers/staging/olpc_dcon/Kconfig" 34 + 33 35 source "drivers/staging/rtl8192u/Kconfig" 34 36 35 37 source "drivers/staging/rtl8192e/Kconfig"
+1
drivers/staging/Makefile
··· 4 4 obj-$(CONFIG_SLICOSS) += slicoss/ 5 5 obj-$(CONFIG_PRISM2_USB) += wlan-ng/ 6 6 obj-$(CONFIG_COMEDI) += comedi/ 7 + obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ 7 8 obj-$(CONFIG_RTL8192U) += rtl8192u/ 8 9 obj-$(CONFIG_RTL8192E) += rtl8192e/ 9 10 obj-$(CONFIG_R8712U) += rtl8712/
+35
drivers/staging/olpc_dcon/Kconfig
··· 1 + config FB_OLPC_DCON 2 + tristate "One Laptop Per Child Display CONtroller support" 3 + depends on OLPC && FB 4 + depends on I2C 5 + depends on (GPIO_CS5535 || GPIO_CS5535=n) 6 + select BACKLIGHT_CLASS_DEVICE 7 + ---help--- 8 + In order to support very low power operation, the XO laptop uses a 9 + secondary Display CONtroller, or DCON. This secondary controller 10 + is present in the video pipeline between the primary display 11 + controller (integrate into the processor or chipset) and the LCD 12 + panel. It allows the main processor/display controller to be 13 + completely powered off while still retaining an image on the display. 14 + This controller is only available on OLPC platforms. Unless you have 15 + one of these platforms, you will want to say 'N'. 16 + 17 + config FB_OLPC_DCON_1 18 + bool "OLPC XO-1 DCON support" 19 + depends on FB_OLPC_DCON && GPIO_CS5535 20 + default y 21 + ---help--- 22 + Enable support for the DCON in XO-1 model laptops. The kernel 23 + communicates with the DCON using model-specific code. If you 24 + have an XO-1 (or if you're unsure what model you have), you should 25 + say 'Y'. 26 + 27 + config FB_OLPC_DCON_1_5 28 + bool "OLPC XO-1.5 DCON support" 29 + depends on FB_OLPC_DCON && ACPI 30 + default y 31 + ---help--- 32 + Enable support for the DCON in XO-1.5 model laptops. The kernel 33 + communicates with the DCON using model-specific code. If you 34 + have an XO-1.5 (or if you're unsure what model you have), you 35 + should say 'Y'.
+6
drivers/staging/olpc_dcon/Makefile
··· 1 + olpc-dcon-objs += olpc_dcon.o 2 + olpc-dcon-$(CONFIG_FB_OLPC_DCON_1) += olpc_dcon_xo_1.o 3 + olpc-dcon-$(CONFIG_FB_OLPC_DCON_1_5) += olpc_dcon_xo_1_5.o 4 + obj-$(CONFIG_FB_OLPC_DCON) += olpc-dcon.o 5 + 6 +
+9
drivers/staging/olpc_dcon/TODO
··· 1 + TODO: 2 + - see if vx855 gpio API can be made similar enough to cs5535 so we can 3 + share more code 4 + - allow simultaneous XO-1 and XO-1.5 support 5 + 6 + Please send patches to Greg Kroah-Hartman <greg@kroah.com> and 7 + copy: 8 + Daniel Drake <dsd@laptop.org> 9 + Jens Frederich <jfrederich@gmail.com>
+813
drivers/staging/olpc_dcon/olpc_dcon.c
··· 1 + /* 2 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse 3 + * 4 + * Copyright © 2006-2007 Red Hat, Inc. 5 + * Copyright © 2006-2007 Advanced Micro Devices, Inc. 6 + * Copyright © 2009 VIA Technology, Inc. 7 + * Copyright (c) 2010-2011 Andres Salomon <dilinger@queued.net> 8 + * 9 + * This program is free software. You can redistribute it and/or 10 + * modify it under the terms of version 2 of the GNU General Public 11 + * License as published by the Free Software Foundation. 12 + */ 13 + 14 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 + 16 + #include <linux/kernel.h> 17 + #include <linux/fb.h> 18 + #include <linux/console.h> 19 + #include <linux/i2c.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/delay.h> 23 + #include <linux/module.h> 24 + #include <linux/backlight.h> 25 + #include <linux/device.h> 26 + #include <linux/uaccess.h> 27 + #include <linux/ctype.h> 28 + #include <linux/reboot.h> 29 + #include <linux/olpc-ec.h> 30 + #include <asm/tsc.h> 31 + #include <asm/olpc.h> 32 + 33 + #include "olpc_dcon.h" 34 + 35 + /* Module definitions */ 36 + 37 + static ushort resumeline = 898; 38 + module_param(resumeline, ushort, 0444); 39 + 40 + static struct dcon_platform_data *pdata; 41 + 42 + /* I2C structures */ 43 + 44 + /* Platform devices */ 45 + static struct platform_device *dcon_device; 46 + 47 + static unsigned short normal_i2c[] = { 0x0d, I2C_CLIENT_END }; 48 + 49 + static s32 dcon_write(struct dcon_priv *dcon, u8 reg, u16 val) 50 + { 51 + return i2c_smbus_write_word_data(dcon->client, reg, val); 52 + } 53 + 54 + static s32 dcon_read(struct dcon_priv *dcon, u8 reg) 55 + { 56 + return i2c_smbus_read_word_data(dcon->client, reg); 57 + } 58 + 59 + /* ===== API functions - these are called by a variety of users ==== */ 60 + 61 + static int dcon_hw_init(struct dcon_priv *dcon, int is_init) 62 + { 63 + u16 ver; 64 + int rc = 0; 65 + 66 + ver = dcon_read(dcon, DCON_REG_ID); 67 + if ((ver >> 8) != 0xDC) { 68 + pr_err("DCON ID not 0xDCxx: 0x%04x instead.\n", ver); 69 + rc = -ENXIO; 70 + goto err; 71 + } 72 + 73 + if (is_init) { 74 + pr_info("Discovered DCON version %x\n", ver & 0xFF); 75 + rc = pdata->init(dcon); 76 + if (rc != 0) { 77 + pr_err("Unable to init.\n"); 78 + goto err; 79 + } 80 + } 81 + 82 + if (ver < 0xdc02) { 83 + dev_err(&dcon->client->dev, 84 + "DCON v1 is unsupported, giving up..\n"); 85 + rc = -ENODEV; 86 + goto err; 87 + } 88 + 89 + /* SDRAM setup/hold time */ 90 + dcon_write(dcon, 0x3a, 0xc040); 91 + dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000); /* clear option bits */ 92 + dcon_write(dcon, DCON_REG_MEM_OPT_A, 93 + MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN); 94 + dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET); 95 + 96 + /* Colour swizzle, AA, no passthrough, backlight */ 97 + if (is_init) { 98 + dcon->disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | 99 + MODE_CSWIZZLE | MODE_COL_AA; 100 + } 101 + dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 102 + 103 + /* Set the scanline to interrupt on during resume */ 104 + dcon_write(dcon, DCON_REG_SCAN_INT, resumeline); 105 + 106 + err: 107 + return rc; 108 + } 109 + 110 + /* 111 + * The smbus doesn't always come back due to what is believed to be 112 + * hardware (power rail) bugs. For older models where this is known to 113 + * occur, our solution is to attempt to wait for the bus to stabilize; 114 + * if it doesn't happen, cut power to the dcon, repower it, and wait 115 + * for the bus to stabilize. Rinse, repeat until we have a working 116 + * smbus. For newer models, we simply BUG(); we want to know if this 117 + * still happens despite the power fixes that have been made! 118 + */ 119 + static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down) 120 + { 121 + unsigned long timeout; 122 + u8 pm; 123 + int x; 124 + 125 + power_up: 126 + if (is_powered_down) { 127 + pm = 1; 128 + x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 129 + if (x) { 130 + pr_warn("unable to force dcon to power up: %d!\n", x); 131 + return x; 132 + } 133 + usleep_range(10000, 11000); /* we'll be conservative */ 134 + } 135 + 136 + pdata->bus_stabilize_wiggle(); 137 + 138 + for (x = -1, timeout = 50; timeout && x < 0; timeout--) { 139 + usleep_range(1000, 1100); 140 + x = dcon_read(dcon, DCON_REG_ID); 141 + } 142 + if (x < 0) { 143 + pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n"); 144 + BUG_ON(olpc_board_at_least(olpc_board(0xc2))); 145 + pm = 0; 146 + olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 147 + msleep(100); 148 + is_powered_down = 1; 149 + goto power_up; /* argh, stupid hardware.. */ 150 + } 151 + 152 + if (is_powered_down) 153 + return dcon_hw_init(dcon, 0); 154 + return 0; 155 + } 156 + 157 + static void dcon_set_backlight(struct dcon_priv *dcon, u8 level) 158 + { 159 + dcon->bl_val = level; 160 + dcon_write(dcon, DCON_REG_BRIGHT, dcon->bl_val); 161 + 162 + /* Purposely turn off the backlight when we go to level 0 */ 163 + if (dcon->bl_val == 0) { 164 + dcon->disp_mode &= ~MODE_BL_ENABLE; 165 + dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 166 + } else if (!(dcon->disp_mode & MODE_BL_ENABLE)) { 167 + dcon->disp_mode |= MODE_BL_ENABLE; 168 + dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 169 + } 170 + } 171 + 172 + /* Set the output type to either color or mono */ 173 + static int dcon_set_mono_mode(struct dcon_priv *dcon, bool enable_mono) 174 + { 175 + if (dcon->mono == enable_mono) 176 + return 0; 177 + 178 + dcon->mono = enable_mono; 179 + 180 + if (enable_mono) { 181 + dcon->disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA); 182 + dcon->disp_mode |= MODE_MONO_LUMA; 183 + } else { 184 + dcon->disp_mode &= ~(MODE_MONO_LUMA); 185 + dcon->disp_mode |= MODE_CSWIZZLE | MODE_COL_AA; 186 + } 187 + 188 + dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 189 + return 0; 190 + } 191 + 192 + /* For now, this will be really stupid - we need to address how 193 + * DCONLOAD works in a sleep and account for it accordingly 194 + */ 195 + 196 + static void dcon_sleep(struct dcon_priv *dcon, bool sleep) 197 + { 198 + int x; 199 + 200 + /* Turn off the backlight and put the DCON to sleep */ 201 + 202 + if (dcon->asleep == sleep) 203 + return; 204 + 205 + if (!olpc_board_at_least(olpc_board(0xc2))) 206 + return; 207 + 208 + if (sleep) { 209 + u8 pm = 0; 210 + 211 + x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 212 + if (x) 213 + pr_warn("unable to force dcon to power down: %d!\n", x); 214 + else 215 + dcon->asleep = sleep; 216 + } else { 217 + /* Only re-enable the backlight if the backlight value is set */ 218 + if (dcon->bl_val != 0) 219 + dcon->disp_mode |= MODE_BL_ENABLE; 220 + x = dcon_bus_stabilize(dcon, 1); 221 + if (x) 222 + pr_warn("unable to reinit dcon hardware: %d!\n", x); 223 + else 224 + dcon->asleep = sleep; 225 + 226 + /* Restore backlight */ 227 + dcon_set_backlight(dcon, dcon->bl_val); 228 + } 229 + 230 + /* We should turn off some stuff in the framebuffer - but what? */ 231 + } 232 + 233 + /* the DCON seems to get confused if we change DCONLOAD too 234 + * frequently -- i.e., approximately faster than frame time. 235 + * normally we don't change it this fast, so in general we won't 236 + * delay here. 237 + */ 238 + static void dcon_load_holdoff(struct dcon_priv *dcon) 239 + { 240 + ktime_t delta_t, now; 241 + 242 + while (1) { 243 + now = ktime_get(); 244 + delta_t = ktime_sub(now, dcon->load_time); 245 + if (ktime_to_ns(delta_t) > NSEC_PER_MSEC * 20) 246 + break; 247 + mdelay(4); 248 + } 249 + } 250 + 251 + static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank) 252 + { 253 + int err; 254 + 255 + console_lock(); 256 + if (!lock_fb_info(dcon->fbinfo)) { 257 + console_unlock(); 258 + dev_err(&dcon->client->dev, "unable to lock framebuffer\n"); 259 + return false; 260 + } 261 + 262 + dcon->ignore_fb_events = true; 263 + err = fb_blank(dcon->fbinfo, 264 + blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); 265 + dcon->ignore_fb_events = false; 266 + unlock_fb_info(dcon->fbinfo); 267 + console_unlock(); 268 + 269 + if (err) { 270 + dev_err(&dcon->client->dev, "couldn't %sblank framebuffer\n", 271 + blank ? "" : "un"); 272 + return false; 273 + } 274 + return true; 275 + } 276 + 277 + /* Set the source of the display (CPU or DCON) */ 278 + static void dcon_source_switch(struct work_struct *work) 279 + { 280 + struct dcon_priv *dcon = container_of(work, struct dcon_priv, 281 + switch_source); 282 + int source = dcon->pending_src; 283 + 284 + if (dcon->curr_src == source) 285 + return; 286 + 287 + dcon_load_holdoff(dcon); 288 + 289 + dcon->switched = false; 290 + 291 + switch (source) { 292 + case DCON_SOURCE_CPU: 293 + pr_info("dcon_source_switch to CPU\n"); 294 + /* Enable the scanline interrupt bit */ 295 + if (dcon_write(dcon, DCON_REG_MODE, 296 + dcon->disp_mode | MODE_SCAN_INT)) 297 + pr_err("couldn't enable scanline interrupt!\n"); 298 + else 299 + /* Wait up to one second for the scanline interrupt */ 300 + wait_event_timeout(dcon->waitq, dcon->switched, HZ); 301 + 302 + if (!dcon->switched) 303 + pr_err("Timeout entering CPU mode; expect a screen glitch.\n"); 304 + 305 + /* Turn off the scanline interrupt */ 306 + if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode)) 307 + pr_err("couldn't disable scanline interrupt!\n"); 308 + 309 + /* 310 + * Ideally we'd like to disable interrupts here so that the 311 + * fb unblanking and DCON turn on happen at a known time value; 312 + * however, we can't do that right now with fb_blank 313 + * messing with semaphores. 314 + * 315 + * For now, we just hope.. 316 + */ 317 + if (!dcon_blank_fb(dcon, false)) { 318 + pr_err("Failed to enter CPU mode\n"); 319 + dcon->pending_src = DCON_SOURCE_DCON; 320 + return; 321 + } 322 + 323 + /* And turn off the DCON */ 324 + pdata->set_dconload(1); 325 + dcon->load_time = ktime_get(); 326 + 327 + pr_info("The CPU has control\n"); 328 + break; 329 + case DCON_SOURCE_DCON: 330 + { 331 + ktime_t delta_t; 332 + 333 + pr_info("dcon_source_switch to DCON\n"); 334 + 335 + /* Clear DCONLOAD - this implies that the DCON is in control */ 336 + pdata->set_dconload(0); 337 + dcon->load_time = ktime_get(); 338 + 339 + wait_event_timeout(dcon->waitq, dcon->switched, HZ/2); 340 + 341 + if (!dcon->switched) { 342 + pr_err("Timeout entering DCON mode; expect a screen glitch.\n"); 343 + } else { 344 + /* sometimes the DCON doesn't follow its own rules, 345 + * and doesn't wait for two vsync pulses before 346 + * ack'ing the frame load with an IRQ. the result 347 + * is that the display shows the *previously* 348 + * loaded frame. we can detect this by looking at 349 + * the time between asserting DCONLOAD and the IRQ -- 350 + * if it's less than 20msec, then the DCON couldn't 351 + * have seen two VSYNC pulses. in that case we 352 + * deassert and reassert, and hope for the best. 353 + * see http://dev.laptop.org/ticket/9664 354 + */ 355 + delta_t = ktime_sub(dcon->irq_time, dcon->load_time); 356 + if (dcon->switched && ktime_to_ns(delta_t) 357 + < NSEC_PER_MSEC * 20) { 358 + pr_err("missed loading, retrying\n"); 359 + pdata->set_dconload(1); 360 + mdelay(41); 361 + pdata->set_dconload(0); 362 + dcon->load_time = ktime_get(); 363 + mdelay(41); 364 + } 365 + } 366 + 367 + dcon_blank_fb(dcon, true); 368 + pr_info("The DCON has control\n"); 369 + break; 370 + } 371 + default: 372 + BUG(); 373 + } 374 + 375 + dcon->curr_src = source; 376 + } 377 + 378 + static void dcon_set_source(struct dcon_priv *dcon, int arg) 379 + { 380 + if (dcon->pending_src == arg) 381 + return; 382 + 383 + dcon->pending_src = arg; 384 + 385 + if (dcon->curr_src != arg) 386 + schedule_work(&dcon->switch_source); 387 + } 388 + 389 + static void dcon_set_source_sync(struct dcon_priv *dcon, int arg) 390 + { 391 + dcon_set_source(dcon, arg); 392 + flush_scheduled_work(); 393 + } 394 + 395 + static ssize_t dcon_mode_show(struct device *dev, 396 + struct device_attribute *attr, char *buf) 397 + { 398 + struct dcon_priv *dcon = dev_get_drvdata(dev); 399 + 400 + return sprintf(buf, "%4.4X\n", dcon->disp_mode); 401 + } 402 + 403 + static ssize_t dcon_sleep_show(struct device *dev, 404 + struct device_attribute *attr, char *buf) 405 + { 406 + struct dcon_priv *dcon = dev_get_drvdata(dev); 407 + 408 + return sprintf(buf, "%d\n", dcon->asleep); 409 + } 410 + 411 + static ssize_t dcon_freeze_show(struct device *dev, 412 + struct device_attribute *attr, char *buf) 413 + { 414 + struct dcon_priv *dcon = dev_get_drvdata(dev); 415 + 416 + return sprintf(buf, "%d\n", dcon->curr_src == DCON_SOURCE_DCON ? 1 : 0); 417 + } 418 + 419 + static ssize_t dcon_mono_show(struct device *dev, 420 + struct device_attribute *attr, char *buf) 421 + { 422 + struct dcon_priv *dcon = dev_get_drvdata(dev); 423 + 424 + return sprintf(buf, "%d\n", dcon->mono); 425 + } 426 + 427 + static ssize_t dcon_resumeline_show(struct device *dev, 428 + struct device_attribute *attr, char *buf) 429 + { 430 + return sprintf(buf, "%d\n", resumeline); 431 + } 432 + 433 + static ssize_t dcon_mono_store(struct device *dev, 434 + struct device_attribute *attr, const char *buf, size_t count) 435 + { 436 + unsigned long enable_mono; 437 + int rc; 438 + 439 + rc = kstrtoul(buf, 10, &enable_mono); 440 + if (rc) 441 + return rc; 442 + 443 + dcon_set_mono_mode(dev_get_drvdata(dev), enable_mono ? true : false); 444 + 445 + return count; 446 + } 447 + 448 + static ssize_t dcon_freeze_store(struct device *dev, 449 + struct device_attribute *attr, const char *buf, size_t count) 450 + { 451 + struct dcon_priv *dcon = dev_get_drvdata(dev); 452 + unsigned long output; 453 + int ret; 454 + 455 + ret = kstrtoul(buf, 10, &output); 456 + if (ret) 457 + return ret; 458 + 459 + pr_info("dcon_freeze_store: %lu\n", output); 460 + 461 + switch (output) { 462 + case 0: 463 + dcon_set_source(dcon, DCON_SOURCE_CPU); 464 + break; 465 + case 1: 466 + dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 467 + break; 468 + case 2: /* normally unused */ 469 + dcon_set_source(dcon, DCON_SOURCE_DCON); 470 + break; 471 + default: 472 + return -EINVAL; 473 + } 474 + 475 + return count; 476 + } 477 + 478 + static ssize_t dcon_resumeline_store(struct device *dev, 479 + struct device_attribute *attr, const char *buf, size_t count) 480 + { 481 + unsigned short rl; 482 + int rc; 483 + 484 + rc = kstrtou16(buf, 10, &rl); 485 + if (rc) 486 + return rc; 487 + 488 + resumeline = rl; 489 + dcon_write(dev_get_drvdata(dev), DCON_REG_SCAN_INT, resumeline); 490 + 491 + return count; 492 + } 493 + 494 + static ssize_t dcon_sleep_store(struct device *dev, 495 + struct device_attribute *attr, const char *buf, size_t count) 496 + { 497 + unsigned long output; 498 + int ret; 499 + 500 + ret = kstrtoul(buf, 10, &output); 501 + if (ret) 502 + return ret; 503 + 504 + dcon_sleep(dev_get_drvdata(dev), output ? true : false); 505 + return count; 506 + } 507 + 508 + static struct device_attribute dcon_device_files[] = { 509 + __ATTR(mode, 0444, dcon_mode_show, NULL), 510 + __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store), 511 + __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store), 512 + __ATTR(monochrome, 0644, dcon_mono_show, dcon_mono_store), 513 + __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), 514 + }; 515 + 516 + static int dcon_bl_update(struct backlight_device *dev) 517 + { 518 + struct dcon_priv *dcon = bl_get_data(dev); 519 + u8 level = dev->props.brightness & 0x0F; 520 + 521 + if (dev->props.power != FB_BLANK_UNBLANK) 522 + level = 0; 523 + 524 + if (level != dcon->bl_val) 525 + dcon_set_backlight(dcon, level); 526 + 527 + /* power down the DCON when the screen is blanked */ 528 + if (!dcon->ignore_fb_events) 529 + dcon_sleep(dcon, !!(dev->props.state & BL_CORE_FBBLANK)); 530 + 531 + return 0; 532 + } 533 + 534 + static int dcon_bl_get(struct backlight_device *dev) 535 + { 536 + struct dcon_priv *dcon = bl_get_data(dev); 537 + 538 + return dcon->bl_val; 539 + } 540 + 541 + static const struct backlight_ops dcon_bl_ops = { 542 + .update_status = dcon_bl_update, 543 + .get_brightness = dcon_bl_get, 544 + }; 545 + 546 + static struct backlight_properties dcon_bl_props = { 547 + .max_brightness = 15, 548 + .type = BACKLIGHT_RAW, 549 + .power = FB_BLANK_UNBLANK, 550 + }; 551 + 552 + static int dcon_reboot_notify(struct notifier_block *nb, 553 + unsigned long foo, void *bar) 554 + { 555 + struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb); 556 + 557 + if (!dcon || !dcon->client) 558 + return NOTIFY_DONE; 559 + 560 + /* Turn off the DCON. Entirely. */ 561 + dcon_write(dcon, DCON_REG_MODE, 0x39); 562 + dcon_write(dcon, DCON_REG_MODE, 0x32); 563 + return NOTIFY_DONE; 564 + } 565 + 566 + static int unfreeze_on_panic(struct notifier_block *nb, 567 + unsigned long e, void *p) 568 + { 569 + pdata->set_dconload(1); 570 + return NOTIFY_DONE; 571 + } 572 + 573 + static struct notifier_block dcon_panic_nb = { 574 + .notifier_call = unfreeze_on_panic, 575 + }; 576 + 577 + static int dcon_detect(struct i2c_client *client, struct i2c_board_info *info) 578 + { 579 + strlcpy(info->type, "olpc_dcon", I2C_NAME_SIZE); 580 + 581 + return 0; 582 + } 583 + 584 + static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) 585 + { 586 + struct dcon_priv *dcon; 587 + int rc, i, j; 588 + 589 + if (!pdata) 590 + return -ENXIO; 591 + 592 + dcon = kzalloc(sizeof(*dcon), GFP_KERNEL); 593 + if (!dcon) 594 + return -ENOMEM; 595 + 596 + dcon->client = client; 597 + init_waitqueue_head(&dcon->waitq); 598 + INIT_WORK(&dcon->switch_source, dcon_source_switch); 599 + dcon->reboot_nb.notifier_call = dcon_reboot_notify; 600 + dcon->reboot_nb.priority = -1; 601 + 602 + i2c_set_clientdata(client, dcon); 603 + 604 + if (num_registered_fb < 1) { 605 + dev_err(&client->dev, "DCON driver requires a registered fb\n"); 606 + rc = -EIO; 607 + goto einit; 608 + } 609 + dcon->fbinfo = registered_fb[0]; 610 + 611 + rc = dcon_hw_init(dcon, 1); 612 + if (rc) 613 + goto einit; 614 + 615 + /* Add the DCON device */ 616 + 617 + dcon_device = platform_device_alloc("dcon", -1); 618 + 619 + if (!dcon_device) { 620 + pr_err("Unable to create the DCON device\n"); 621 + rc = -ENOMEM; 622 + goto eirq; 623 + } 624 + rc = platform_device_add(dcon_device); 625 + platform_set_drvdata(dcon_device, dcon); 626 + 627 + if (rc) { 628 + pr_err("Unable to add the DCON device\n"); 629 + goto edev; 630 + } 631 + 632 + for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) { 633 + rc = device_create_file(&dcon_device->dev, 634 + &dcon_device_files[i]); 635 + if (rc) { 636 + dev_err(&dcon_device->dev, "Cannot create sysfs file\n"); 637 + goto ecreate; 638 + } 639 + } 640 + 641 + dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F; 642 + 643 + /* Add the backlight device for the DCON */ 644 + dcon_bl_props.brightness = dcon->bl_val; 645 + dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev, 646 + dcon, &dcon_bl_ops, &dcon_bl_props); 647 + if (IS_ERR(dcon->bl_dev)) { 648 + dev_err(&client->dev, "cannot register backlight dev (%ld)\n", 649 + PTR_ERR(dcon->bl_dev)); 650 + dcon->bl_dev = NULL; 651 + } 652 + 653 + register_reboot_notifier(&dcon->reboot_nb); 654 + atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb); 655 + 656 + return 0; 657 + 658 + ecreate: 659 + for (j = 0; j < i; j++) 660 + device_remove_file(&dcon_device->dev, &dcon_device_files[j]); 661 + edev: 662 + platform_device_unregister(dcon_device); 663 + dcon_device = NULL; 664 + eirq: 665 + free_irq(DCON_IRQ, dcon); 666 + einit: 667 + kfree(dcon); 668 + return rc; 669 + } 670 + 671 + static int dcon_remove(struct i2c_client *client) 672 + { 673 + struct dcon_priv *dcon = i2c_get_clientdata(client); 674 + 675 + unregister_reboot_notifier(&dcon->reboot_nb); 676 + atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb); 677 + 678 + free_irq(DCON_IRQ, dcon); 679 + 680 + backlight_device_unregister(dcon->bl_dev); 681 + 682 + if (dcon_device) 683 + platform_device_unregister(dcon_device); 684 + cancel_work_sync(&dcon->switch_source); 685 + 686 + kfree(dcon); 687 + 688 + return 0; 689 + } 690 + 691 + #ifdef CONFIG_PM 692 + static int dcon_suspend(struct device *dev) 693 + { 694 + struct i2c_client *client = to_i2c_client(dev); 695 + struct dcon_priv *dcon = i2c_get_clientdata(client); 696 + 697 + if (!dcon->asleep) { 698 + /* Set up the DCON to have the source */ 699 + dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 700 + } 701 + 702 + return 0; 703 + } 704 + 705 + static int dcon_resume(struct device *dev) 706 + { 707 + struct i2c_client *client = to_i2c_client(dev); 708 + struct dcon_priv *dcon = i2c_get_clientdata(client); 709 + 710 + if (!dcon->asleep) { 711 + dcon_bus_stabilize(dcon, 0); 712 + dcon_set_source(dcon, DCON_SOURCE_CPU); 713 + } 714 + 715 + return 0; 716 + } 717 + 718 + #else 719 + 720 + #define dcon_suspend NULL 721 + #define dcon_resume NULL 722 + 723 + #endif /* CONFIG_PM */ 724 + 725 + irqreturn_t dcon_interrupt(int irq, void *id) 726 + { 727 + struct dcon_priv *dcon = id; 728 + u8 status; 729 + 730 + if (pdata->read_status(&status)) 731 + return IRQ_NONE; 732 + 733 + switch (status & 3) { 734 + case 3: 735 + pr_debug("DCONLOAD_MISSED interrupt\n"); 736 + break; 737 + 738 + case 2: /* switch to DCON mode */ 739 + case 1: /* switch to CPU mode */ 740 + dcon->switched = true; 741 + dcon->irq_time = ktime_get(); 742 + wake_up(&dcon->waitq); 743 + break; 744 + 745 + case 0: 746 + /* workaround resume case: the DCON (on 1.5) doesn't 747 + * ever assert status 0x01 when switching to CPU mode 748 + * during resume. this is because DCONLOAD is de-asserted 749 + * _immediately_ upon exiting S3, so the actual release 750 + * of the DCON happened long before this point. 751 + * see http://dev.laptop.org/ticket/9869 752 + */ 753 + if (dcon->curr_src != dcon->pending_src && !dcon->switched) { 754 + dcon->switched = true; 755 + dcon->irq_time = ktime_get(); 756 + wake_up(&dcon->waitq); 757 + pr_debug("switching w/ status 0/0\n"); 758 + } else { 759 + pr_debug("scanline interrupt w/CPU\n"); 760 + } 761 + } 762 + 763 + return IRQ_HANDLED; 764 + } 765 + 766 + static const struct dev_pm_ops dcon_pm_ops = { 767 + .suspend = dcon_suspend, 768 + .resume = dcon_resume, 769 + }; 770 + 771 + static const struct i2c_device_id dcon_idtable[] = { 772 + { "olpc_dcon", 0 }, 773 + { } 774 + }; 775 + MODULE_DEVICE_TABLE(i2c, dcon_idtable); 776 + 777 + static struct i2c_driver dcon_driver = { 778 + .driver = { 779 + .name = "olpc_dcon", 780 + .pm = &dcon_pm_ops, 781 + }, 782 + .class = I2C_CLASS_DDC | I2C_CLASS_HWMON, 783 + .id_table = dcon_idtable, 784 + .probe = dcon_probe, 785 + .remove = dcon_remove, 786 + .detect = dcon_detect, 787 + .address_list = normal_i2c, 788 + }; 789 + 790 + static int __init olpc_dcon_init(void) 791 + { 792 + #ifdef CONFIG_FB_OLPC_DCON_1_5 793 + /* XO-1.5 */ 794 + if (olpc_board_at_least(olpc_board(0xd0))) 795 + pdata = &dcon_pdata_xo_1_5; 796 + #endif 797 + #ifdef CONFIG_FB_OLPC_DCON_1 798 + if (!pdata) 799 + pdata = &dcon_pdata_xo_1; 800 + #endif 801 + 802 + return i2c_add_driver(&dcon_driver); 803 + } 804 + 805 + static void __exit olpc_dcon_exit(void) 806 + { 807 + i2c_del_driver(&dcon_driver); 808 + } 809 + 810 + module_init(olpc_dcon_init); 811 + module_exit(olpc_dcon_exit); 812 + 813 + MODULE_LICENSE("GPL");
+111
drivers/staging/olpc_dcon/olpc_dcon.h
··· 1 + #ifndef OLPC_DCON_H_ 2 + #define OLPC_DCON_H_ 3 + 4 + #include <linux/notifier.h> 5 + #include <linux/workqueue.h> 6 + 7 + /* DCON registers */ 8 + 9 + #define DCON_REG_ID 0 10 + #define DCON_REG_MODE 1 11 + 12 + #define MODE_PASSTHRU (1<<0) 13 + #define MODE_SLEEP (1<<1) 14 + #define MODE_SLEEP_AUTO (1<<2) 15 + #define MODE_BL_ENABLE (1<<3) 16 + #define MODE_BLANK (1<<4) 17 + #define MODE_CSWIZZLE (1<<5) 18 + #define MODE_COL_AA (1<<6) 19 + #define MODE_MONO_LUMA (1<<7) 20 + #define MODE_SCAN_INT (1<<8) 21 + #define MODE_CLOCKDIV (1<<9) 22 + #define MODE_DEBUG (1<<14) 23 + #define MODE_SELFTEST (1<<15) 24 + 25 + #define DCON_REG_HRES 0x2 26 + #define DCON_REG_HTOTAL 0x3 27 + #define DCON_REG_HSYNC_WIDTH 0x4 28 + #define DCON_REG_VRES 0x5 29 + #define DCON_REG_VTOTAL 0x6 30 + #define DCON_REG_VSYNC_WIDTH 0x7 31 + #define DCON_REG_TIMEOUT 0x8 32 + #define DCON_REG_SCAN_INT 0x9 33 + #define DCON_REG_BRIGHT 0xa 34 + #define DCON_REG_MEM_OPT_A 0x41 35 + #define DCON_REG_MEM_OPT_B 0x42 36 + 37 + /* Load Delay Locked Loop (DLL) settings for clock delay */ 38 + #define MEM_DLL_CLOCK_DELAY (1<<0) 39 + /* Memory controller power down function */ 40 + #define MEM_POWER_DOWN (1<<8) 41 + /* Memory controller software reset */ 42 + #define MEM_SOFT_RESET (1<<0) 43 + 44 + /* Status values */ 45 + 46 + #define DCONSTAT_SCANINT 0 47 + #define DCONSTAT_SCANINT_DCON 1 48 + #define DCONSTAT_DISPLAYLOAD 2 49 + #define DCONSTAT_MISSED 3 50 + 51 + /* Source values */ 52 + 53 + #define DCON_SOURCE_DCON 0 54 + #define DCON_SOURCE_CPU 1 55 + 56 + /* Interrupt */ 57 + #define DCON_IRQ 6 58 + 59 + struct dcon_priv { 60 + struct i2c_client *client; 61 + struct fb_info *fbinfo; 62 + struct backlight_device *bl_dev; 63 + 64 + wait_queue_head_t waitq; 65 + struct work_struct switch_source; 66 + struct notifier_block reboot_nb; 67 + 68 + /* Shadow register for the DCON_REG_MODE register */ 69 + u8 disp_mode; 70 + 71 + /* The current backlight value - this saves us some smbus traffic */ 72 + u8 bl_val; 73 + 74 + /* Current source, initialized at probe time */ 75 + int curr_src; 76 + 77 + /* Desired source */ 78 + int pending_src; 79 + 80 + /* Variables used during switches */ 81 + bool switched; 82 + ktime_t irq_time; 83 + ktime_t load_time; 84 + 85 + /* Current output type; true == mono, false == color */ 86 + bool mono; 87 + bool asleep; 88 + /* This get set while controlling fb blank state from the driver */ 89 + bool ignore_fb_events; 90 + }; 91 + 92 + struct dcon_platform_data { 93 + int (*init)(struct dcon_priv *); 94 + void (*bus_stabilize_wiggle)(void); 95 + void (*set_dconload)(int); 96 + int (*read_status)(u8 *); 97 + }; 98 + 99 + #include <linux/interrupt.h> 100 + 101 + irqreturn_t dcon_interrupt(int irq, void *id); 102 + 103 + #ifdef CONFIG_FB_OLPC_DCON_1 104 + extern struct dcon_platform_data dcon_pdata_xo_1; 105 + #endif 106 + 107 + #ifdef CONFIG_FB_OLPC_DCON_1_5 108 + extern struct dcon_platform_data dcon_pdata_xo_1_5; 109 + #endif 110 + 111 + #endif
+205
drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
··· 1 + /* 2 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse 3 + * 4 + * Copyright © 2006-2007 Red Hat, Inc. 5 + * Copyright © 2006-2007 Advanced Micro Devices, Inc. 6 + * Copyright © 2009 VIA Technology, Inc. 7 + * Copyright (c) 2010 Andres Salomon <dilinger@queued.net> 8 + * 9 + * This program is free software. You can redistribute it and/or 10 + * modify it under the terms of version 2 of the GNU General Public 11 + * License as published by the Free Software Foundation. 12 + */ 13 + 14 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 + 16 + #include <linux/cs5535.h> 17 + #include <linux/gpio.h> 18 + #include <linux/delay.h> 19 + #include <asm/olpc.h> 20 + 21 + #include "olpc_dcon.h" 22 + 23 + static int dcon_init_xo_1(struct dcon_priv *dcon) 24 + { 25 + unsigned char lob; 26 + 27 + if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) { 28 + pr_err("failed to request STAT0 GPIO\n"); 29 + return -EIO; 30 + } 31 + if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) { 32 + pr_err("failed to request STAT1 GPIO\n"); 33 + goto err_gp_stat1; 34 + } 35 + if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) { 36 + pr_err("failed to request IRQ GPIO\n"); 37 + goto err_gp_irq; 38 + } 39 + if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) { 40 + pr_err("failed to request LOAD GPIO\n"); 41 + goto err_gp_load; 42 + } 43 + if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) { 44 + pr_err("failed to request BLANK GPIO\n"); 45 + goto err_gp_blank; 46 + } 47 + 48 + /* Turn off the event enable for GPIO7 just to be safe */ 49 + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); 50 + 51 + /* 52 + * Determine the current state by reading the GPIO bit; earlier 53 + * stages of the boot process have established the state. 54 + * 55 + * Note that we read GPIO_OUTPUT_VAL rather than GPIO_READ_BACK here; 56 + * this is because OFW will disable input for the pin and set a value.. 57 + * READ_BACK will only contain a valid value if input is enabled and 58 + * then a value is set. So, future readings of the pin can use 59 + * READ_BACK, but the first one cannot. Awesome, huh? 60 + */ 61 + dcon->curr_src = cs5535_gpio_isset(OLPC_GPIO_DCON_LOAD, GPIO_OUTPUT_VAL) 62 + ? DCON_SOURCE_CPU 63 + : DCON_SOURCE_DCON; 64 + dcon->pending_src = dcon->curr_src; 65 + 66 + /* Set the directions for the GPIO pins */ 67 + gpio_direction_input(OLPC_GPIO_DCON_STAT0); 68 + gpio_direction_input(OLPC_GPIO_DCON_STAT1); 69 + gpio_direction_input(OLPC_GPIO_DCON_IRQ); 70 + gpio_direction_input(OLPC_GPIO_DCON_BLANK); 71 + gpio_direction_output(OLPC_GPIO_DCON_LOAD, 72 + dcon->curr_src == DCON_SOURCE_CPU); 73 + 74 + /* Set up the interrupt mappings */ 75 + 76 + /* Set the IRQ to pair 2 */ 77 + cs5535_gpio_setup_event(OLPC_GPIO_DCON_IRQ, 2, 0); 78 + 79 + /* Enable group 2 to trigger the DCON interrupt */ 80 + cs5535_gpio_set_irq(2, DCON_IRQ); 81 + 82 + /* Select edge level for interrupt (in PIC) */ 83 + lob = inb(0x4d0); 84 + lob &= ~(1 << DCON_IRQ); 85 + outb(lob, 0x4d0); 86 + 87 + /* Register the interrupt handler */ 88 + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", dcon)) { 89 + pr_err("failed to request DCON's irq\n"); 90 + goto err_req_irq; 91 + } 92 + 93 + /* Clear INV_EN for GPIO7 (DCONIRQ) */ 94 + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_INVERT); 95 + 96 + /* Enable filter for GPIO12 (DCONBLANK) */ 97 + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_FILTER); 98 + 99 + /* Disable filter for GPIO7 */ 100 + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_FILTER); 101 + 102 + /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ 103 + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_EVENT_COUNT); 104 + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_EVENT_COUNT); 105 + 106 + /* Add GPIO12 to the Filter Event Pair #7 */ 107 + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_FE7_SEL); 108 + 109 + /* Turn off negative Edge Enable for GPIO12 */ 110 + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_EN); 111 + 112 + /* Enable negative Edge Enable for GPIO7 */ 113 + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_EN); 114 + 115 + /* Zero the filter amount for Filter Event Pair #7 */ 116 + cs5535_gpio_set(0, GPIO_FLTR7_AMOUNT); 117 + 118 + /* Clear the negative edge status for GPIO7 and GPIO12 */ 119 + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); 120 + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS); 121 + 122 + /* FIXME: Clear the positive status as well, just to be sure */ 123 + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS); 124 + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS); 125 + 126 + /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ 127 + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); 128 + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_EVENTS_ENABLE); 129 + 130 + return 0; 131 + 132 + err_req_irq: 133 + gpio_free(OLPC_GPIO_DCON_BLANK); 134 + err_gp_blank: 135 + gpio_free(OLPC_GPIO_DCON_LOAD); 136 + err_gp_load: 137 + gpio_free(OLPC_GPIO_DCON_IRQ); 138 + err_gp_irq: 139 + gpio_free(OLPC_GPIO_DCON_STAT1); 140 + err_gp_stat1: 141 + gpio_free(OLPC_GPIO_DCON_STAT0); 142 + return -EIO; 143 + } 144 + 145 + static void dcon_wiggle_xo_1(void) 146 + { 147 + int x; 148 + 149 + /* 150 + * According to HiMax, when powering the DCON up we should hold 151 + * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON 152 + * state machine to reset to a (sane) initial state. Mitch Bradley 153 + * did some testing and discovered that holding for 16 SMB_CLK cycles 154 + * worked a lot more reliably, so that's what we do here. 155 + * 156 + * According to the cs5536 spec, to set GPIO14 to SMB_CLK we must 157 + * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and 158 + * GPIO15. 159 + */ 160 + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); 161 + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); 162 + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_ENABLE); 163 + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); 164 + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); 165 + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); 166 + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX2); 167 + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); 168 + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); 169 + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); 170 + 171 + for (x = 0; x < 16; x++) { 172 + udelay(5); 173 + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); 174 + udelay(5); 175 + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); 176 + } 177 + udelay(5); 178 + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); 179 + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); 180 + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); 181 + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); 182 + } 183 + 184 + static void dcon_set_dconload_1(int val) 185 + { 186 + gpio_set_value(OLPC_GPIO_DCON_LOAD, val); 187 + } 188 + 189 + static int dcon_read_status_xo_1(u8 *status) 190 + { 191 + *status = gpio_get_value(OLPC_GPIO_DCON_STAT0); 192 + *status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1; 193 + 194 + /* Clear the negative edge status for GPIO7 */ 195 + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); 196 + 197 + return 0; 198 + } 199 + 200 + struct dcon_platform_data dcon_pdata_xo_1 = { 201 + .init = dcon_init_xo_1, 202 + .bus_stabilize_wiggle = dcon_wiggle_xo_1, 203 + .set_dconload = dcon_set_dconload_1, 204 + .read_status = dcon_read_status_xo_1, 205 + };
+161
drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
··· 1 + /* 2 + * Copyright (c) 2009,2010 One Laptop per Child 3 + * 4 + * This program is free software. You can redistribute it and/or 5 + * modify it under the terms of version 2 of the GNU General Public 6 + * License as published by the Free Software Foundation. 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/delay.h> 13 + #include <linux/gpio.h> 14 + #include <asm/olpc.h> 15 + 16 + /* TODO: this eventually belongs in linux/vx855.h */ 17 + #define NR_VX855_GPI 14 18 + #define NR_VX855_GPO 13 19 + #define NR_VX855_GPIO 15 20 + 21 + #define VX855_GPI(n) (n) 22 + #define VX855_GPO(n) (NR_VX855_GPI + (n)) 23 + #define VX855_GPIO(n) (NR_VX855_GPI + NR_VX855_GPO + (n)) 24 + 25 + #include "olpc_dcon.h" 26 + 27 + /* Hardware setup on the XO 1.5: 28 + * DCONLOAD connects to VX855_GPIO1 (not SMBCK2) 29 + * DCONBLANK connects to VX855_GPIO8 (not SSPICLK) unused in driver 30 + * DCONSTAT0 connects to VX855_GPI10 (not SSPISDI) 31 + * DCONSTAT1 connects to VX855_GPI11 (not nSSPISS) 32 + * DCONIRQ connects to VX855_GPIO12 33 + * DCONSMBDATA connects to VX855 graphics CRTSPD 34 + * DCONSMBCLK connects to VX855 graphics CRTSPCLK 35 + */ 36 + 37 + #define VX855_GENL_PURPOSE_OUTPUT 0x44c /* PMIO_Rx4c-4f */ 38 + #define VX855_GPI_STATUS_CHG 0x450 /* PMIO_Rx50 */ 39 + #define VX855_GPI_SCI_SMI 0x452 /* PMIO_Rx52 */ 40 + #define BIT_GPIO12 0x40 41 + 42 + #define PREFIX "OLPC DCON:" 43 + 44 + static void dcon_clear_irq(void) 45 + { 46 + /* irq status will appear in PMIO_Rx50[6] (RW1C) on gpio12 */ 47 + outb(BIT_GPIO12, VX855_GPI_STATUS_CHG); 48 + } 49 + 50 + static int dcon_was_irq(void) 51 + { 52 + u_int8_t tmp; 53 + 54 + /* irq status will appear in PMIO_Rx50[6] on gpio12 */ 55 + tmp = inb(VX855_GPI_STATUS_CHG); 56 + return !!(tmp & BIT_GPIO12); 57 + 58 + return 0; 59 + } 60 + 61 + static int dcon_init_xo_1_5(struct dcon_priv *dcon) 62 + { 63 + unsigned int irq; 64 + 65 + dcon_clear_irq(); 66 + 67 + /* set PMIO_Rx52[6] to enable SCI/SMI on gpio12 */ 68 + outb(inb(VX855_GPI_SCI_SMI)|BIT_GPIO12, VX855_GPI_SCI_SMI); 69 + 70 + /* Determine the current state of DCONLOAD, likely set by firmware */ 71 + /* GPIO1 */ 72 + dcon->curr_src = (inl(VX855_GENL_PURPOSE_OUTPUT) & 0x1000) ? 73 + DCON_SOURCE_CPU : DCON_SOURCE_DCON; 74 + dcon->pending_src = dcon->curr_src; 75 + 76 + /* we're sharing the IRQ with ACPI */ 77 + irq = acpi_gbl_FADT.sci_interrupt; 78 + if (request_irq(irq, &dcon_interrupt, IRQF_SHARED, "DCON", dcon)) { 79 + pr_err("DCON (IRQ%d) allocation failed\n", irq); 80 + return 1; 81 + } 82 + 83 + return 0; 84 + } 85 + 86 + static void set_i2c_line(int sda, int scl) 87 + { 88 + unsigned char tmp; 89 + unsigned int port = 0x26; 90 + 91 + /* FIXME: This directly accesses the CRT GPIO controller !!! */ 92 + outb(port, 0x3c4); 93 + tmp = inb(0x3c5); 94 + 95 + if (scl) 96 + tmp |= 0x20; 97 + else 98 + tmp &= ~0x20; 99 + 100 + if (sda) 101 + tmp |= 0x10; 102 + else 103 + tmp &= ~0x10; 104 + 105 + tmp |= 0x01; 106 + 107 + outb(port, 0x3c4); 108 + outb(tmp, 0x3c5); 109 + } 110 + 111 + 112 + static void dcon_wiggle_xo_1_5(void) 113 + { 114 + int x; 115 + 116 + /* 117 + * According to HiMax, when powering the DCON up we should hold 118 + * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON 119 + * state machine to reset to a (sane) initial state. Mitch Bradley 120 + * did some testing and discovered that holding for 16 SMB_CLK cycles 121 + * worked a lot more reliably, so that's what we do here. 122 + */ 123 + set_i2c_line(1, 1); 124 + 125 + for (x = 0; x < 16; x++) { 126 + udelay(5); 127 + set_i2c_line(1, 0); 128 + udelay(5); 129 + set_i2c_line(1, 1); 130 + } 131 + udelay(5); 132 + 133 + /* set PMIO_Rx52[6] to enable SCI/SMI on gpio12 */ 134 + outb(inb(VX855_GPI_SCI_SMI)|BIT_GPIO12, VX855_GPI_SCI_SMI); 135 + } 136 + 137 + static void dcon_set_dconload_xo_1_5(int val) 138 + { 139 + gpio_set_value(VX855_GPIO(1), val); 140 + } 141 + 142 + static int dcon_read_status_xo_1_5(u8 *status) 143 + { 144 + if (!dcon_was_irq()) 145 + return -1; 146 + 147 + /* i believe this is the same as "inb(0x44b) & 3" */ 148 + *status = gpio_get_value(VX855_GPI(10)); 149 + *status |= gpio_get_value(VX855_GPI(11)) << 1; 150 + 151 + dcon_clear_irq(); 152 + 153 + return 0; 154 + } 155 + 156 + struct dcon_platform_data dcon_pdata_xo_1_5 = { 157 + .init = dcon_init_xo_1_5, 158 + .bus_stabilize_wiggle = dcon_wiggle_xo_1_5, 159 + .set_dconload = dcon_set_dconload_xo_1_5, 160 + .read_status = dcon_read_status_xo_1_5, 161 + };
+1
drivers/staging/rdma/hfi1/Kconfig
··· 2 2 tristate "Intel OPA Gen1 support" 3 3 depends on X86_64 && INFINIBAND_RDMAVT 4 4 select MMU_NOTIFIER 5 + select CRC32 5 6 default m 6 7 ---help--- 7 8 This is a low-level driver for Intel OPA Gen1 adapter.