diff options
Diffstat (limited to 'drivers')
38 files changed, 2706 insertions, 98 deletions
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index b02c4ffa4db0..0a9a774a7e1e 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c | |||
@@ -1642,13 +1642,12 @@ static int sata_dwc_probe(struct platform_device *ofdev) | |||
1642 | const struct ata_port_info *ppi[] = { &pi, NULL }; | 1642 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
1643 | 1643 | ||
1644 | /* Allocate DWC SATA device */ | 1644 | /* Allocate DWC SATA device */ |
1645 | hsdev = kmalloc(sizeof(*hsdev), GFP_KERNEL); | 1645 | hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); |
1646 | if (hsdev == NULL) { | 1646 | if (hsdev == NULL) { |
1647 | dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); | 1647 | dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); |
1648 | err = -ENOMEM; | 1648 | err = -ENOMEM; |
1649 | goto error; | 1649 | goto error; |
1650 | } | 1650 | } |
1651 | memset(hsdev, 0, sizeof(*hsdev)); | ||
1652 | 1651 | ||
1653 | /* Ioremap SATA registers */ | 1652 | /* Ioremap SATA registers */ |
1654 | base = of_iomap(ofdev->dev.of_node, 0); | 1653 | base = of_iomap(ofdev->dev.of_node, 0); |
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 281902d3f7ec..0debc17c8e28 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c | |||
@@ -173,7 +173,6 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id) | |||
173 | struct proc_event *ev; | 173 | struct proc_event *ev; |
174 | struct timespec ts; | 174 | struct timespec ts; |
175 | __u8 buffer[CN_PROC_MSG_SIZE]; | 175 | __u8 buffer[CN_PROC_MSG_SIZE]; |
176 | struct task_struct *tracer; | ||
177 | 176 | ||
178 | if (atomic_read(&proc_event_num_listeners) < 1) | 177 | if (atomic_read(&proc_event_num_listeners) < 1) |
179 | return; | 178 | return; |
diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index 0dd0f633b18d..30da70d06a6d 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c | |||
@@ -45,13 +45,13 @@ static int __init pci_eisa_init(struct pci_dev *pdev, | |||
45 | return 0; | 45 | return 0; |
46 | } | 46 | } |
47 | 47 | ||
48 | static struct pci_device_id pci_eisa_pci_tbl[] = { | 48 | static struct pci_device_id __initdata pci_eisa_pci_tbl[] = { |
49 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 49 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
50 | PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 }, | 50 | PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 }, |
51 | { 0, } | 51 | { 0, } |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static struct pci_driver pci_eisa_driver = { | 54 | static struct pci_driver __initdata pci_eisa_driver = { |
55 | .name = "pci_eisa", | 55 | .name = "pci_eisa", |
56 | .id_table = pci_eisa_pci_tbl, | 56 | .id_table = pci_eisa_pci_tbl, |
57 | .probe = pci_eisa_init, | 57 | .probe = pci_eisa_init, |
diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c index c19cd2c39fa6..f10fc521951b 100644 --- a/drivers/firmware/sigma.c +++ b/drivers/firmware/sigma.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/firmware.h> | 11 | #include <linux/firmware.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/module.h> | ||
14 | #include <linux/sigma.h> | 15 | #include <linux/sigma.h> |
15 | 16 | ||
16 | /* Return: 0==OK, <0==error, =1 ==no more actions */ | 17 | /* Return: 0==OK, <0==error, =1 ==no more actions */ |
@@ -113,3 +114,5 @@ int process_sigma_firmware(struct i2c_client *client, const char *name) | |||
113 | return ret; | 114 | return ret; |
114 | } | 115 | } |
115 | EXPORT_SYMBOL(process_sigma_firmware); | 116 | EXPORT_SYMBOL(process_sigma_firmware); |
117 | |||
118 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c index d15e09b0ae0b..7525e0311e59 100644 --- a/drivers/gpu/drm/drm_scatter.c +++ b/drivers/gpu/drm/drm_scatter.c | |||
@@ -83,30 +83,26 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) | |||
83 | if (dev->sg) | 83 | if (dev->sg) |
84 | return -EINVAL; | 84 | return -EINVAL; |
85 | 85 | ||
86 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 86 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
87 | if (!entry) | 87 | if (!entry) |
88 | return -ENOMEM; | 88 | return -ENOMEM; |
89 | 89 | ||
90 | memset(entry, 0, sizeof(*entry)); | ||
91 | pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; | 90 | pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; |
92 | DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); | 91 | DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); |
93 | 92 | ||
94 | entry->pages = pages; | 93 | entry->pages = pages; |
95 | entry->pagelist = kmalloc(pages * sizeof(*entry->pagelist), GFP_KERNEL); | 94 | entry->pagelist = kcalloc(pages, sizeof(*entry->pagelist), GFP_KERNEL); |
96 | if (!entry->pagelist) { | 95 | if (!entry->pagelist) { |
97 | kfree(entry); | 96 | kfree(entry); |
98 | return -ENOMEM; | 97 | return -ENOMEM; |
99 | } | 98 | } |
100 | 99 | ||
101 | memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); | 100 | entry->busaddr = kcalloc(pages, sizeof(*entry->busaddr), GFP_KERNEL); |
102 | |||
103 | entry->busaddr = kmalloc(pages * sizeof(*entry->busaddr), GFP_KERNEL); | ||
104 | if (!entry->busaddr) { | 101 | if (!entry->busaddr) { |
105 | kfree(entry->pagelist); | 102 | kfree(entry->pagelist); |
106 | kfree(entry); | 103 | kfree(entry); |
107 | return -ENOMEM; | 104 | return -ENOMEM; |
108 | } | 105 | } |
109 | memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr)); | ||
110 | 106 | ||
111 | entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT); | 107 | entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT); |
112 | if (!entry->virtual) { | 108 | if (!entry->virtual) { |
diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c index ed95155c4b1d..988548efea92 100644 --- a/drivers/gpu/drm/radeon/radeon_mem.c +++ b/drivers/gpu/drm/radeon/radeon_mem.c | |||
@@ -139,7 +139,7 @@ static int init_heap(struct mem_block **heap, int start, int size) | |||
139 | if (!blocks) | 139 | if (!blocks) |
140 | return -ENOMEM; | 140 | return -ENOMEM; |
141 | 141 | ||
142 | *heap = kmalloc(sizeof(**heap), GFP_KERNEL); | 142 | *heap = kzalloc(sizeof(**heap), GFP_KERNEL); |
143 | if (!*heap) { | 143 | if (!*heap) { |
144 | kfree(blocks); | 144 | kfree(blocks); |
145 | return -ENOMEM; | 145 | return -ENOMEM; |
@@ -150,7 +150,6 @@ static int init_heap(struct mem_block **heap, int start, int size) | |||
150 | blocks->file_priv = NULL; | 150 | blocks->file_priv = NULL; |
151 | blocks->next = blocks->prev = *heap; | 151 | blocks->next = blocks->prev = *heap; |
152 | 152 | ||
153 | memset(*heap, 0, sizeof(**heap)); | ||
154 | (*heap)->file_priv = (struct drm_file *) - 1; | 153 | (*heap)->file_priv = (struct drm_file *) - 1; |
155 | (*heap)->next = (*heap)->prev = blocks; | 154 | (*heap)->next = (*heap)->prev = blocks; |
156 | return 0; | 155 | return 0; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index f1a52f9e7298..07ce02da78a4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | |||
@@ -585,11 +585,10 @@ int vmw_overlay_init(struct vmw_private *dev_priv) | |||
585 | return -ENOSYS; | 585 | return -ENOSYS; |
586 | } | 586 | } |
587 | 587 | ||
588 | overlay = kmalloc(sizeof(*overlay), GFP_KERNEL); | 588 | overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); |
589 | if (!overlay) | 589 | if (!overlay) |
590 | return -ENOMEM; | 590 | return -ENOMEM; |
591 | 591 | ||
592 | memset(overlay, 0, sizeof(*overlay)); | ||
593 | mutex_init(&overlay->mutex); | 592 | mutex_init(&overlay->mutex); |
594 | for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { | 593 | for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) { |
595 | overlay->stream[i].buf = NULL; | 594 | overlay->stream[i].buf = NULL; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 5408b1b7996f..bfe1bcce7f8a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -612,11 +612,9 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | |||
612 | srf->sizes[0].height == 64 && | 612 | srf->sizes[0].height == 64 && |
613 | srf->format == SVGA3D_A8R8G8B8) { | 613 | srf->format == SVGA3D_A8R8G8B8) { |
614 | 614 | ||
615 | srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL); | 615 | /* allocate image area and clear it */ |
616 | /* clear the image */ | 616 | srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL); |
617 | if (srf->snooper.image) { | 617 | if (!srf->snooper.image) { |
618 | memset(srf->snooper.image, 0x00, 64 * 64 * 4); | ||
619 | } else { | ||
620 | DRM_ERROR("Failed to allocate cursor_image\n"); | 618 | DRM_ERROR("Failed to allocate cursor_image\n"); |
621 | ret = -ENOMEM; | 619 | ret = -ENOMEM; |
622 | goto out_err1; | 620 | goto out_err1; |
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 8a1021f2e319..c72f1c0b5e63 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c | |||
@@ -1171,10 +1171,9 @@ static int vga_arb_open(struct inode *inode, struct file *file) | |||
1171 | 1171 | ||
1172 | pr_debug("%s\n", __func__); | 1172 | pr_debug("%s\n", __func__); |
1173 | 1173 | ||
1174 | priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL); | 1174 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1175 | if (priv == NULL) | 1175 | if (priv == NULL) |
1176 | return -ENOMEM; | 1176 | return -ENOMEM; |
1177 | memset(priv, 0, sizeof(*priv)); | ||
1178 | spin_lock_init(&priv->lock); | 1177 | spin_lock_init(&priv->lock); |
1179 | file->private_data = priv; | 1178 | file->private_data = priv; |
1180 | 1179 | ||
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6c21c2986ca1..b591e726a6fa 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -365,6 +365,7 @@ config LEDS_NS2 | |||
365 | config LEDS_NETXBIG | 365 | config LEDS_NETXBIG |
366 | tristate "LED support for Big Network series LEDs" | 366 | tristate "LED support for Big Network series LEDs" |
367 | depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2 | 367 | depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2 |
368 | depends on LEDS_CLASS | ||
368 | default y | 369 | default y |
369 | help | 370 | help |
370 | This option enable support for LEDs found on the LaCie 2Big | 371 | This option enable support for LEDs found on the LaCie 2Big |
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 4d7ce7631acf..3dd7090a9a9b 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c | |||
@@ -68,17 +68,16 @@ | |||
68 | #define LM3530_ALS2_IMP_SHIFT (4) | 68 | #define LM3530_ALS2_IMP_SHIFT (4) |
69 | 69 | ||
70 | /* Zone Boundary Register defaults */ | 70 | /* Zone Boundary Register defaults */ |
71 | #define LM3530_DEF_ZB_0 (0x33) | 71 | #define LM3530_ALS_ZB_MAX (4) |
72 | #define LM3530_DEF_ZB_1 (0x66) | 72 | #define LM3530_ALS_WINDOW_mV (1000) |
73 | #define LM3530_DEF_ZB_2 (0x99) | 73 | #define LM3530_ALS_OFFSET_mV (4) |
74 | #define LM3530_DEF_ZB_3 (0xCC) | ||
75 | 74 | ||
76 | /* Zone Target Register defaults */ | 75 | /* Zone Target Register defaults */ |
77 | #define LM3530_DEF_ZT_0 (0x19) | 76 | #define LM3530_DEF_ZT_0 (0x7F) |
78 | #define LM3530_DEF_ZT_1 (0x33) | 77 | #define LM3530_DEF_ZT_1 (0x66) |
79 | #define LM3530_DEF_ZT_2 (0x4C) | 78 | #define LM3530_DEF_ZT_2 (0x4C) |
80 | #define LM3530_DEF_ZT_3 (0x66) | 79 | #define LM3530_DEF_ZT_3 (0x33) |
81 | #define LM3530_DEF_ZT_4 (0x7F) | 80 | #define LM3530_DEF_ZT_4 (0x19) |
82 | 81 | ||
83 | struct lm3530_mode_map { | 82 | struct lm3530_mode_map { |
84 | const char *mode; | 83 | const char *mode; |
@@ -150,6 +149,8 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) | |||
150 | u8 als_imp_sel = 0; | 149 | u8 als_imp_sel = 0; |
151 | u8 brightness; | 150 | u8 brightness; |
152 | u8 reg_val[LM3530_REG_MAX]; | 151 | u8 reg_val[LM3530_REG_MAX]; |
152 | u8 zones[LM3530_ALS_ZB_MAX]; | ||
153 | u32 als_vmin, als_vmax, als_vstep; | ||
153 | struct lm3530_platform_data *pltfm = drvdata->pdata; | 154 | struct lm3530_platform_data *pltfm = drvdata->pdata; |
154 | struct i2c_client *client = drvdata->client; | 155 | struct i2c_client *client = drvdata->client; |
155 | 156 | ||
@@ -161,6 +162,26 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) | |||
161 | gen_config |= (LM3530_ENABLE_I2C); | 162 | gen_config |= (LM3530_ENABLE_I2C); |
162 | 163 | ||
163 | if (drvdata->mode == LM3530_BL_MODE_ALS) { | 164 | if (drvdata->mode == LM3530_BL_MODE_ALS) { |
165 | if (pltfm->als_vmax == 0) { | ||
166 | pltfm->als_vmin = als_vmin = 0; | ||
167 | pltfm->als_vmin = als_vmax = LM3530_ALS_WINDOW_mV; | ||
168 | } | ||
169 | |||
170 | als_vmin = pltfm->als_vmin; | ||
171 | als_vmax = pltfm->als_vmax; | ||
172 | |||
173 | if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV) | ||
174 | pltfm->als_vmax = als_vmax = | ||
175 | als_vmin + LM3530_ALS_WINDOW_mV; | ||
176 | |||
177 | /* n zone boundary makes n+1 zones */ | ||
178 | als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1); | ||
179 | |||
180 | for (i = 0; i < LM3530_ALS_ZB_MAX; i++) | ||
181 | zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) + | ||
182 | als_vstep + (i * als_vstep)) * LED_FULL) | ||
183 | / 1000; | ||
184 | |||
164 | als_config = | 185 | als_config = |
165 | (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) | | 186 | (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) | |
166 | (LM3530_ENABLE_ALS) | | 187 | (LM3530_ENABLE_ALS) | |
@@ -169,6 +190,7 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) | |||
169 | als_imp_sel = | 190 | als_imp_sel = |
170 | (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) | | 191 | (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) | |
171 | (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT); | 192 | (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT); |
193 | |||
172 | } | 194 | } |
173 | 195 | ||
174 | if (drvdata->mode == LM3530_BL_MODE_PWM) | 196 | if (drvdata->mode == LM3530_BL_MODE_PWM) |
@@ -190,10 +212,10 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) | |||
190 | reg_val[3] = 0x00; /* LM3530_ALS_ZONE_REG */ | 212 | reg_val[3] = 0x00; /* LM3530_ALS_ZONE_REG */ |
191 | reg_val[4] = als_imp_sel; /* LM3530_ALS_IMP_SELECT */ | 213 | reg_val[4] = als_imp_sel; /* LM3530_ALS_IMP_SELECT */ |
192 | reg_val[5] = brightness; /* LM3530_BRT_CTRL_REG */ | 214 | reg_val[5] = brightness; /* LM3530_BRT_CTRL_REG */ |
193 | reg_val[6] = LM3530_DEF_ZB_0; /* LM3530_ALS_ZB0_REG */ | 215 | reg_val[6] = zones[0]; /* LM3530_ALS_ZB0_REG */ |
194 | reg_val[7] = LM3530_DEF_ZB_1; /* LM3530_ALS_ZB1_REG */ | 216 | reg_val[7] = zones[1]; /* LM3530_ALS_ZB1_REG */ |
195 | reg_val[8] = LM3530_DEF_ZB_2; /* LM3530_ALS_ZB2_REG */ | 217 | reg_val[8] = zones[2]; /* LM3530_ALS_ZB2_REG */ |
196 | reg_val[9] = LM3530_DEF_ZB_3; /* LM3530_ALS_ZB3_REG */ | 218 | reg_val[9] = zones[3]; /* LM3530_ALS_ZB3_REG */ |
197 | reg_val[10] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */ | 219 | reg_val[10] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */ |
198 | reg_val[11] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */ | 220 | reg_val[11] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */ |
199 | reg_val[12] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */ | 221 | reg_val[12] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */ |
@@ -265,6 +287,24 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev, | |||
265 | } | 287 | } |
266 | } | 288 | } |
267 | 289 | ||
290 | static ssize_t lm3530_mode_get(struct device *dev, | ||
291 | struct device_attribute *attr, char *buf) | ||
292 | { | ||
293 | struct i2c_client *client = container_of( | ||
294 | dev->parent, struct i2c_client, dev); | ||
295 | struct lm3530_data *drvdata = i2c_get_clientdata(client); | ||
296 | int i, len = 0; | ||
297 | |||
298 | for (i = 0; i < ARRAY_SIZE(mode_map); i++) | ||
299 | if (drvdata->mode == mode_map[i].mode_val) | ||
300 | len += sprintf(buf + len, "[%s] ", mode_map[i].mode); | ||
301 | else | ||
302 | len += sprintf(buf + len, "%s ", mode_map[i].mode); | ||
303 | |||
304 | len += sprintf(buf + len, "\n"); | ||
305 | |||
306 | return len; | ||
307 | } | ||
268 | 308 | ||
269 | static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute | 309 | static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute |
270 | *attr, const char *buf, size_t size) | 310 | *attr, const char *buf, size_t size) |
@@ -298,8 +338,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute | |||
298 | 338 | ||
299 | return sizeof(drvdata->mode); | 339 | return sizeof(drvdata->mode); |
300 | } | 340 | } |
301 | 341 | static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set); | |
302 | static DEVICE_ATTR(mode, 0644, NULL, lm3530_mode_set); | ||
303 | 342 | ||
304 | static int __devinit lm3530_probe(struct i2c_client *client, | 343 | static int __devinit lm3530_probe(struct i2c_client *client, |
305 | const struct i2c_device_id *id) | 344 | const struct i2c_device_id *id) |
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index cc1dc4817fac..9fc122c81f06 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c | |||
@@ -744,7 +744,7 @@ fail1: | |||
744 | return ret; | 744 | return ret; |
745 | } | 745 | } |
746 | 746 | ||
747 | static int lp5521_remove(struct i2c_client *client) | 747 | static int __devexit lp5521_remove(struct i2c_client *client) |
748 | { | 748 | { |
749 | struct lp5521_chip *chip = i2c_get_clientdata(client); | 749 | struct lp5521_chip *chip = i2c_get_clientdata(client); |
750 | int i; | 750 | int i; |
@@ -775,7 +775,7 @@ static struct i2c_driver lp5521_driver = { | |||
775 | .name = "lp5521", | 775 | .name = "lp5521", |
776 | }, | 776 | }, |
777 | .probe = lp5521_probe, | 777 | .probe = lp5521_probe, |
778 | .remove = lp5521_remove, | 778 | .remove = __devexit_p(lp5521_remove), |
779 | .id_table = lp5521_id, | 779 | .id_table = lp5521_id, |
780 | }; | 780 | }; |
781 | 781 | ||
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index ab6d18f5c39f..1757396b20b3 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c | |||
@@ -127,17 +127,19 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, | |||
127 | struct led_type *types) | 127 | struct led_type *types) |
128 | { | 128 | { |
129 | struct sunfire_drvdata *p; | 129 | struct sunfire_drvdata *p; |
130 | int i, err = -EINVAL; | 130 | int i, err; |
131 | 131 | ||
132 | if (pdev->num_resources != 1) { | 132 | if (pdev->num_resources != 1) { |
133 | printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", | 133 | printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", |
134 | pdev->num_resources); | 134 | pdev->num_resources); |
135 | err = -EINVAL; | ||
135 | goto out; | 136 | goto out; |
136 | } | 137 | } |
137 | 138 | ||
138 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 139 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
139 | if (!p) { | 140 | if (!p) { |
140 | printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); | 141 | printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); |
142 | err = -ENOMEM; | ||
141 | goto out; | 143 | goto out; |
142 | } | 144 | } |
143 | 145 | ||
@@ -160,14 +162,14 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, | |||
160 | 162 | ||
161 | dev_set_drvdata(&pdev->dev, p); | 163 | dev_set_drvdata(&pdev->dev, p); |
162 | 164 | ||
163 | err = 0; | 165 | return 0; |
164 | out: | ||
165 | return err; | ||
166 | 166 | ||
167 | out_unregister_led_cdevs: | 167 | out_unregister_led_cdevs: |
168 | for (i--; i >= 0; i--) | 168 | for (i--; i >= 0; i--) |
169 | led_classdev_unregister(&p->leds[i].led_cdev); | 169 | led_classdev_unregister(&p->leds[i].led_cdev); |
170 | goto out; | 170 | kfree(p); |
171 | out: | ||
172 | return err; | ||
171 | } | 173 | } |
172 | 174 | ||
173 | static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) | 175 | static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4e349cd98bcf..0a4d86c6c4a4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -245,8 +245,7 @@ config SGI_XP | |||
245 | 245 | ||
246 | config CS5535_MFGPT | 246 | config CS5535_MFGPT |
247 | tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" | 247 | tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" |
248 | depends on PCI | 248 | depends on PCI && X86 && MFD_CS5535 |
249 | depends on X86 | ||
250 | default n | 249 | default n |
251 | help | 250 | help |
252 | This driver provides access to MFGPT functionality for other | 251 | This driver provides access to MFGPT functionality for other |
@@ -490,6 +489,15 @@ config PCH_PHUB | |||
490 | To compile this driver as a module, choose M here: the module will | 489 | To compile this driver as a module, choose M here: the module will |
491 | be called pch_phub. | 490 | be called pch_phub. |
492 | 491 | ||
492 | config USB_SWITCH_FSA9480 | ||
493 | tristate "FSA9480 USB Switch" | ||
494 | depends on I2C | ||
495 | help | ||
496 | The FSA9480 is a USB port accessory detector and switch. | ||
497 | The FSA9480 is fully controlled using I2C and enables USB data, | ||
498 | stereo and mono audio, video, microphone and UART data to use | ||
499 | a common connector port. | ||
500 | |||
493 | source "drivers/misc/c2port/Kconfig" | 501 | source "drivers/misc/c2port/Kconfig" |
494 | source "drivers/misc/eeprom/Kconfig" | 502 | source "drivers/misc/eeprom/Kconfig" |
495 | source "drivers/misc/cb710/Kconfig" | 503 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5f03172cc0b5..33282157bc3c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -46,3 +46,4 @@ obj-y += ti-st/ | |||
46 | obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o | 46 | obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o |
47 | obj-y += lis3lv02d/ | 47 | obj-y += lis3lv02d/ |
48 | obj-y += carma/ | 48 | obj-y += carma/ |
49 | obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o | ||
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 9118613af321..26cf12ca7f50 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig | |||
@@ -70,4 +70,29 @@ config EEPROM_93CX6 | |||
70 | 70 | ||
71 | If unsure, say N. | 71 | If unsure, say N. |
72 | 72 | ||
73 | config EEPROM_93XX46 | ||
74 | tristate "Microwire EEPROM 93XX46 support" | ||
75 | depends on SPI && SYSFS | ||
76 | help | ||
77 | Driver for the microwire EEPROM chipsets 93xx46x. The driver | ||
78 | supports both read and write commands and also the command to | ||
79 | erase the whole EEPROM. | ||
80 | |||
81 | This driver can also be built as a module. If so, the module | ||
82 | will be called eeprom_93xx46. | ||
83 | |||
84 | If unsure, say N. | ||
85 | |||
86 | config EEPROM_DIGSY_MTC_CFG | ||
87 | bool "DigsyMTC display configuration EEPROMs device" | ||
88 | depends on PPC_MPC5200_GPIO && GPIOLIB && SPI_GPIO | ||
89 | help | ||
90 | This option enables access to display configuration EEPROMs | ||
91 | on digsy_mtc board. You have to additionally select Microwire | ||
92 | EEPROM 93XX46 driver. sysfs entries will be created for that | ||
93 | EEPROM allowing to read/write the configuration data or to | ||
94 | erase the whole EEPROM. | ||
95 | |||
96 | If unsure, say N. | ||
97 | |||
73 | endmenu | 98 | endmenu |
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index df3d68ffa9d1..fc1e81d29267 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile | |||
@@ -3,3 +3,5 @@ obj-$(CONFIG_EEPROM_AT25) += at25.o | |||
3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o | 3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o |
4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o | 4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o |
5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
6 | obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o | ||
7 | obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o | ||
diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c new file mode 100644 index 000000000000..66d9e1baeae5 --- /dev/null +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * EEPROMs access control driver for display configuration EEPROMs | ||
3 | * on DigsyMTC board. | ||
4 | * | ||
5 | * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/gpio.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/spi/spi_gpio.h> | ||
17 | #include <linux/eeprom_93xx46.h> | ||
18 | |||
19 | #define GPIO_EEPROM_CLK 216 | ||
20 | #define GPIO_EEPROM_CS 210 | ||
21 | #define GPIO_EEPROM_DI 217 | ||
22 | #define GPIO_EEPROM_DO 249 | ||
23 | #define GPIO_EEPROM_OE 255 | ||
24 | #define EE_SPI_BUS_NUM 1 | ||
25 | |||
26 | static void digsy_mtc_op_prepare(void *p) | ||
27 | { | ||
28 | /* enable */ | ||
29 | gpio_set_value(GPIO_EEPROM_OE, 0); | ||
30 | } | ||
31 | |||
32 | static void digsy_mtc_op_finish(void *p) | ||
33 | { | ||
34 | /* disable */ | ||
35 | gpio_set_value(GPIO_EEPROM_OE, 1); | ||
36 | } | ||
37 | |||
38 | struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = { | ||
39 | .flags = EE_ADDR8, | ||
40 | .prepare = digsy_mtc_op_prepare, | ||
41 | .finish = digsy_mtc_op_finish, | ||
42 | }; | ||
43 | |||
44 | static struct spi_gpio_platform_data eeprom_spi_gpio_data = { | ||
45 | .sck = GPIO_EEPROM_CLK, | ||
46 | .mosi = GPIO_EEPROM_DI, | ||
47 | .miso = GPIO_EEPROM_DO, | ||
48 | .num_chipselect = 1, | ||
49 | }; | ||
50 | |||
51 | static struct platform_device digsy_mtc_eeprom = { | ||
52 | .name = "spi_gpio", | ||
53 | .id = EE_SPI_BUS_NUM, | ||
54 | .dev = { | ||
55 | .platform_data = &eeprom_spi_gpio_data, | ||
56 | }, | ||
57 | }; | ||
58 | |||
59 | static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = { | ||
60 | { | ||
61 | .modalias = "93xx46", | ||
62 | .max_speed_hz = 1000000, | ||
63 | .bus_num = EE_SPI_BUS_NUM, | ||
64 | .chip_select = 0, | ||
65 | .mode = SPI_MODE_0, | ||
66 | .controller_data = (void *)GPIO_EEPROM_CS, | ||
67 | .platform_data = &digsy_mtc_eeprom_data, | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static int __init digsy_mtc_eeprom_devices_init(void) | ||
72 | { | ||
73 | int ret; | ||
74 | |||
75 | ret = gpio_request_one(GPIO_EEPROM_OE, GPIOF_OUT_INIT_HIGH, | ||
76 | "93xx46 EEPROMs OE"); | ||
77 | if (ret) { | ||
78 | pr_err("can't request gpio %d\n", GPIO_EEPROM_OE); | ||
79 | return ret; | ||
80 | } | ||
81 | spi_register_board_info(digsy_mtc_eeprom_info, | ||
82 | ARRAY_SIZE(digsy_mtc_eeprom_info)); | ||
83 | return platform_device_register(&digsy_mtc_eeprom); | ||
84 | } | ||
85 | device_initcall(digsy_mtc_eeprom_devices_init); | ||
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c new file mode 100644 index 000000000000..0c7ebb1e19e5 --- /dev/null +++ b/drivers/misc/eeprom/eeprom_93xx46.c | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | * Driver for 93xx46 EEPROMs | ||
3 | * | ||
4 | * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/sysfs.h> | ||
20 | #include <linux/eeprom_93xx46.h> | ||
21 | |||
22 | #define OP_START 0x4 | ||
23 | #define OP_WRITE (OP_START | 0x1) | ||
24 | #define OP_READ (OP_START | 0x2) | ||
25 | #define ADDR_EWDS 0x00 | ||
26 | #define ADDR_ERAL 0x20 | ||
27 | #define ADDR_EWEN 0x30 | ||
28 | |||
29 | struct eeprom_93xx46_dev { | ||
30 | struct spi_device *spi; | ||
31 | struct eeprom_93xx46_platform_data *pdata; | ||
32 | struct bin_attribute bin; | ||
33 | struct mutex lock; | ||
34 | int addrlen; | ||
35 | }; | ||
36 | |||
37 | static ssize_t | ||
38 | eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj, | ||
39 | struct bin_attribute *bin_attr, | ||
40 | char *buf, loff_t off, size_t count) | ||
41 | { | ||
42 | struct eeprom_93xx46_dev *edev; | ||
43 | struct device *dev; | ||
44 | struct spi_message m; | ||
45 | struct spi_transfer t[2]; | ||
46 | int bits, ret; | ||
47 | u16 cmd_addr; | ||
48 | |||
49 | dev = container_of(kobj, struct device, kobj); | ||
50 | edev = dev_get_drvdata(dev); | ||
51 | |||
52 | if (unlikely(off >= edev->bin.size)) | ||
53 | return 0; | ||
54 | if ((off + count) > edev->bin.size) | ||
55 | count = edev->bin.size - off; | ||
56 | if (unlikely(!count)) | ||
57 | return count; | ||
58 | |||
59 | cmd_addr = OP_READ << edev->addrlen; | ||
60 | |||
61 | if (edev->addrlen == 7) { | ||
62 | cmd_addr |= off & 0x7f; | ||
63 | bits = 10; | ||
64 | } else { | ||
65 | cmd_addr |= off & 0x3f; | ||
66 | bits = 9; | ||
67 | } | ||
68 | |||
69 | dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", | ||
70 | cmd_addr, edev->spi->max_speed_hz); | ||
71 | |||
72 | spi_message_init(&m); | ||
73 | memset(t, 0, sizeof(t)); | ||
74 | |||
75 | t[0].tx_buf = (char *)&cmd_addr; | ||
76 | t[0].len = 2; | ||
77 | t[0].bits_per_word = bits; | ||
78 | spi_message_add_tail(&t[0], &m); | ||
79 | |||
80 | t[1].rx_buf = buf; | ||
81 | t[1].len = count; | ||
82 | t[1].bits_per_word = 8; | ||
83 | spi_message_add_tail(&t[1], &m); | ||
84 | |||
85 | mutex_lock(&edev->lock); | ||
86 | |||
87 | if (edev->pdata->prepare) | ||
88 | edev->pdata->prepare(edev); | ||
89 | |||
90 | ret = spi_sync(edev->spi, &m); | ||
91 | /* have to wait at least Tcsl ns */ | ||
92 | ndelay(250); | ||
93 | if (ret) { | ||
94 | dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", | ||
95 | count, (int)off, ret); | ||
96 | } | ||
97 | |||
98 | if (edev->pdata->finish) | ||
99 | edev->pdata->finish(edev); | ||
100 | |||
101 | mutex_unlock(&edev->lock); | ||
102 | return ret ? : count; | ||
103 | } | ||
104 | |||
105 | static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) | ||
106 | { | ||
107 | struct spi_message m; | ||
108 | struct spi_transfer t; | ||
109 | int bits, ret; | ||
110 | u16 cmd_addr; | ||
111 | |||
112 | cmd_addr = OP_START << edev->addrlen; | ||
113 | if (edev->addrlen == 7) { | ||
114 | cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; | ||
115 | bits = 10; | ||
116 | } else { | ||
117 | cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); | ||
118 | bits = 9; | ||
119 | } | ||
120 | |||
121 | dev_dbg(&edev->spi->dev, "ew cmd 0x%04x\n", cmd_addr); | ||
122 | |||
123 | spi_message_init(&m); | ||
124 | memset(&t, 0, sizeof(t)); | ||
125 | |||
126 | t.tx_buf = &cmd_addr; | ||
127 | t.len = 2; | ||
128 | t.bits_per_word = bits; | ||
129 | spi_message_add_tail(&t, &m); | ||
130 | |||
131 | mutex_lock(&edev->lock); | ||
132 | |||
133 | if (edev->pdata->prepare) | ||
134 | edev->pdata->prepare(edev); | ||
135 | |||
136 | ret = spi_sync(edev->spi, &m); | ||
137 | /* have to wait at least Tcsl ns */ | ||
138 | ndelay(250); | ||
139 | if (ret) | ||
140 | dev_err(&edev->spi->dev, "erase/write %sable error %d\n", | ||
141 | is_on ? "en" : "dis", ret); | ||
142 | |||
143 | if (edev->pdata->finish) | ||
144 | edev->pdata->finish(edev); | ||
145 | |||
146 | mutex_unlock(&edev->lock); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static ssize_t | ||
151 | eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, | ||
152 | const char *buf, unsigned off) | ||
153 | { | ||
154 | struct spi_message m; | ||
155 | struct spi_transfer t[2]; | ||
156 | int bits, data_len, ret; | ||
157 | u16 cmd_addr; | ||
158 | |||
159 | cmd_addr = OP_WRITE << edev->addrlen; | ||
160 | |||
161 | if (edev->addrlen == 7) { | ||
162 | cmd_addr |= off & 0x7f; | ||
163 | bits = 10; | ||
164 | data_len = 1; | ||
165 | } else { | ||
166 | cmd_addr |= off & 0x3f; | ||
167 | bits = 9; | ||
168 | data_len = 2; | ||
169 | } | ||
170 | |||
171 | dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); | ||
172 | |||
173 | spi_message_init(&m); | ||
174 | memset(t, 0, sizeof(t)); | ||
175 | |||
176 | t[0].tx_buf = (char *)&cmd_addr; | ||
177 | t[0].len = 2; | ||
178 | t[0].bits_per_word = bits; | ||
179 | spi_message_add_tail(&t[0], &m); | ||
180 | |||
181 | t[1].tx_buf = buf; | ||
182 | t[1].len = data_len; | ||
183 | t[1].bits_per_word = 8; | ||
184 | spi_message_add_tail(&t[1], &m); | ||
185 | |||
186 | ret = spi_sync(edev->spi, &m); | ||
187 | /* have to wait program cycle time Twc ms */ | ||
188 | mdelay(6); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static ssize_t | ||
193 | eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj, | ||
194 | struct bin_attribute *bin_attr, | ||
195 | char *buf, loff_t off, size_t count) | ||
196 | { | ||
197 | struct eeprom_93xx46_dev *edev; | ||
198 | struct device *dev; | ||
199 | int i, ret, step = 1; | ||
200 | |||
201 | dev = container_of(kobj, struct device, kobj); | ||
202 | edev = dev_get_drvdata(dev); | ||
203 | |||
204 | if (unlikely(off >= edev->bin.size)) | ||
205 | return 0; | ||
206 | if ((off + count) > edev->bin.size) | ||
207 | count = edev->bin.size - off; | ||
208 | if (unlikely(!count)) | ||
209 | return count; | ||
210 | |||
211 | /* only write even number of bytes on 16-bit devices */ | ||
212 | if (edev->addrlen == 6) { | ||
213 | step = 2; | ||
214 | count &= ~1; | ||
215 | } | ||
216 | |||
217 | /* erase/write enable */ | ||
218 | ret = eeprom_93xx46_ew(edev, 1); | ||
219 | if (ret) | ||
220 | return ret; | ||
221 | |||
222 | mutex_lock(&edev->lock); | ||
223 | |||
224 | if (edev->pdata->prepare) | ||
225 | edev->pdata->prepare(edev); | ||
226 | |||
227 | for (i = 0; i < count; i += step) { | ||
228 | ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); | ||
229 | if (ret) { | ||
230 | dev_err(&edev->spi->dev, "write failed at %d: %d\n", | ||
231 | (int)off + i, ret); | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | if (edev->pdata->finish) | ||
237 | edev->pdata->finish(edev); | ||
238 | |||
239 | mutex_unlock(&edev->lock); | ||
240 | |||
241 | /* erase/write disable */ | ||
242 | eeprom_93xx46_ew(edev, 0); | ||
243 | return ret ? : count; | ||
244 | } | ||
245 | |||
246 | static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) | ||
247 | { | ||
248 | struct eeprom_93xx46_platform_data *pd = edev->pdata; | ||
249 | struct spi_message m; | ||
250 | struct spi_transfer t; | ||
251 | int bits, ret; | ||
252 | u16 cmd_addr; | ||
253 | |||
254 | cmd_addr = OP_START << edev->addrlen; | ||
255 | if (edev->addrlen == 7) { | ||
256 | cmd_addr |= ADDR_ERAL << 1; | ||
257 | bits = 10; | ||
258 | } else { | ||
259 | cmd_addr |= ADDR_ERAL; | ||
260 | bits = 9; | ||
261 | } | ||
262 | |||
263 | spi_message_init(&m); | ||
264 | memset(&t, 0, sizeof(t)); | ||
265 | |||
266 | t.tx_buf = &cmd_addr; | ||
267 | t.len = 2; | ||
268 | t.bits_per_word = bits; | ||
269 | spi_message_add_tail(&t, &m); | ||
270 | |||
271 | mutex_lock(&edev->lock); | ||
272 | |||
273 | if (edev->pdata->prepare) | ||
274 | edev->pdata->prepare(edev); | ||
275 | |||
276 | ret = spi_sync(edev->spi, &m); | ||
277 | if (ret) | ||
278 | dev_err(&edev->spi->dev, "erase error %d\n", ret); | ||
279 | /* have to wait erase cycle time Tec ms */ | ||
280 | mdelay(6); | ||
281 | |||
282 | if (pd->finish) | ||
283 | pd->finish(edev); | ||
284 | |||
285 | mutex_unlock(&edev->lock); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static ssize_t eeprom_93xx46_store_erase(struct device *dev, | ||
290 | struct device_attribute *attr, | ||
291 | const char *buf, size_t count) | ||
292 | { | ||
293 | struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); | ||
294 | int erase = 0, ret; | ||
295 | |||
296 | sscanf(buf, "%d", &erase); | ||
297 | if (erase) { | ||
298 | ret = eeprom_93xx46_ew(edev, 1); | ||
299 | if (ret) | ||
300 | return ret; | ||
301 | ret = eeprom_93xx46_eral(edev); | ||
302 | if (ret) | ||
303 | return ret; | ||
304 | ret = eeprom_93xx46_ew(edev, 0); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | } | ||
308 | return count; | ||
309 | } | ||
310 | static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); | ||
311 | |||
312 | static int __devinit eeprom_93xx46_probe(struct spi_device *spi) | ||
313 | { | ||
314 | struct eeprom_93xx46_platform_data *pd; | ||
315 | struct eeprom_93xx46_dev *edev; | ||
316 | int err; | ||
317 | |||
318 | pd = spi->dev.platform_data; | ||
319 | if (!pd) { | ||
320 | dev_err(&spi->dev, "missing platform data\n"); | ||
321 | return -ENODEV; | ||
322 | } | ||
323 | |||
324 | edev = kzalloc(sizeof(*edev), GFP_KERNEL); | ||
325 | if (!edev) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | if (pd->flags & EE_ADDR8) | ||
329 | edev->addrlen = 7; | ||
330 | else if (pd->flags & EE_ADDR16) | ||
331 | edev->addrlen = 6; | ||
332 | else { | ||
333 | dev_err(&spi->dev, "unspecified address type\n"); | ||
334 | err = -EINVAL; | ||
335 | goto fail; | ||
336 | } | ||
337 | |||
338 | mutex_init(&edev->lock); | ||
339 | |||
340 | edev->spi = spi_dev_get(spi); | ||
341 | edev->pdata = pd; | ||
342 | |||
343 | sysfs_bin_attr_init(&edev->bin); | ||
344 | edev->bin.attr.name = "eeprom"; | ||
345 | edev->bin.attr.mode = S_IRUSR; | ||
346 | edev->bin.read = eeprom_93xx46_bin_read; | ||
347 | edev->bin.size = 128; | ||
348 | if (!(pd->flags & EE_READONLY)) { | ||
349 | edev->bin.write = eeprom_93xx46_bin_write; | ||
350 | edev->bin.attr.mode |= S_IWUSR; | ||
351 | } | ||
352 | |||
353 | err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin); | ||
354 | if (err) | ||
355 | goto fail; | ||
356 | |||
357 | dev_info(&spi->dev, "%d-bit eeprom %s\n", | ||
358 | (pd->flags & EE_ADDR8) ? 8 : 16, | ||
359 | (pd->flags & EE_READONLY) ? "(readonly)" : ""); | ||
360 | |||
361 | if (!(pd->flags & EE_READONLY)) { | ||
362 | if (device_create_file(&spi->dev, &dev_attr_erase)) | ||
363 | dev_err(&spi->dev, "can't create erase interface\n"); | ||
364 | } | ||
365 | |||
366 | dev_set_drvdata(&spi->dev, edev); | ||
367 | return 0; | ||
368 | fail: | ||
369 | kfree(edev); | ||
370 | return err; | ||
371 | } | ||
372 | |||
373 | static int __devexit eeprom_93xx46_remove(struct spi_device *spi) | ||
374 | { | ||
375 | struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); | ||
376 | |||
377 | if (!(edev->pdata->flags & EE_READONLY)) | ||
378 | device_remove_file(&spi->dev, &dev_attr_erase); | ||
379 | |||
380 | sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin); | ||
381 | dev_set_drvdata(&spi->dev, NULL); | ||
382 | kfree(edev); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static struct spi_driver eeprom_93xx46_driver = { | ||
387 | .driver = { | ||
388 | .name = "93xx46", | ||
389 | .owner = THIS_MODULE, | ||
390 | }, | ||
391 | .probe = eeprom_93xx46_probe, | ||
392 | .remove = __devexit_p(eeprom_93xx46_remove), | ||
393 | }; | ||
394 | |||
395 | static int __init eeprom_93xx46_init(void) | ||
396 | { | ||
397 | return spi_register_driver(&eeprom_93xx46_driver); | ||
398 | } | ||
399 | module_init(eeprom_93xx46_init); | ||
400 | |||
401 | static void __exit eeprom_93xx46_exit(void) | ||
402 | { | ||
403 | spi_unregister_driver(&eeprom_93xx46_driver); | ||
404 | } | ||
405 | module_exit(eeprom_93xx46_exit); | ||
406 | |||
407 | MODULE_LICENSE("GPL"); | ||
408 | MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); | ||
409 | MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); | ||
410 | MODULE_ALIAS("spi:93xx46"); | ||
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c new file mode 100644 index 000000000000..5325a7e70dcf --- /dev/null +++ b/drivers/misc/fsa9480.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * fsa9480.c - FSA9480 micro USB switch device driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics | ||
5 | * Minkyu Kang <mk7.kang@samsung.com> | ||
6 | * Wonguk Jeong <wonguk.jeong@samsung.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 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/platform_data/fsa9480.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | |||
25 | /* FSA9480 I2C registers */ | ||
26 | #define FSA9480_REG_DEVID 0x01 | ||
27 | #define FSA9480_REG_CTRL 0x02 | ||
28 | #define FSA9480_REG_INT1 0x03 | ||
29 | #define FSA9480_REG_INT2 0x04 | ||
30 | #define FSA9480_REG_INT1_MASK 0x05 | ||
31 | #define FSA9480_REG_INT2_MASK 0x06 | ||
32 | #define FSA9480_REG_ADC 0x07 | ||
33 | #define FSA9480_REG_TIMING1 0x08 | ||
34 | #define FSA9480_REG_TIMING2 0x09 | ||
35 | #define FSA9480_REG_DEV_T1 0x0a | ||
36 | #define FSA9480_REG_DEV_T2 0x0b | ||
37 | #define FSA9480_REG_BTN1 0x0c | ||
38 | #define FSA9480_REG_BTN2 0x0d | ||
39 | #define FSA9480_REG_CK 0x0e | ||
40 | #define FSA9480_REG_CK_INT1 0x0f | ||
41 | #define FSA9480_REG_CK_INT2 0x10 | ||
42 | #define FSA9480_REG_CK_INTMASK1 0x11 | ||
43 | #define FSA9480_REG_CK_INTMASK2 0x12 | ||
44 | #define FSA9480_REG_MANSW1 0x13 | ||
45 | #define FSA9480_REG_MANSW2 0x14 | ||
46 | |||
47 | /* Control */ | ||
48 | #define CON_SWITCH_OPEN (1 << 4) | ||
49 | #define CON_RAW_DATA (1 << 3) | ||
50 | #define CON_MANUAL_SW (1 << 2) | ||
51 | #define CON_WAIT (1 << 1) | ||
52 | #define CON_INT_MASK (1 << 0) | ||
53 | #define CON_MASK (CON_SWITCH_OPEN | CON_RAW_DATA | \ | ||
54 | CON_MANUAL_SW | CON_WAIT) | ||
55 | |||
56 | /* Device Type 1 */ | ||
57 | #define DEV_USB_OTG (1 << 7) | ||
58 | #define DEV_DEDICATED_CHG (1 << 6) | ||
59 | #define DEV_USB_CHG (1 << 5) | ||
60 | #define DEV_CAR_KIT (1 << 4) | ||
61 | #define DEV_UART (1 << 3) | ||
62 | #define DEV_USB (1 << 2) | ||
63 | #define DEV_AUDIO_2 (1 << 1) | ||
64 | #define DEV_AUDIO_1 (1 << 0) | ||
65 | |||
66 | #define DEV_T1_USB_MASK (DEV_USB_OTG | DEV_USB) | ||
67 | #define DEV_T1_UART_MASK (DEV_UART) | ||
68 | #define DEV_T1_CHARGER_MASK (DEV_DEDICATED_CHG | DEV_USB_CHG) | ||
69 | |||
70 | /* Device Type 2 */ | ||
71 | #define DEV_AV (1 << 6) | ||
72 | #define DEV_TTY (1 << 5) | ||
73 | #define DEV_PPD (1 << 4) | ||
74 | #define DEV_JIG_UART_OFF (1 << 3) | ||
75 | #define DEV_JIG_UART_ON (1 << 2) | ||
76 | #define DEV_JIG_USB_OFF (1 << 1) | ||
77 | #define DEV_JIG_USB_ON (1 << 0) | ||
78 | |||
79 | #define DEV_T2_USB_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON) | ||
80 | #define DEV_T2_UART_MASK (DEV_JIG_UART_OFF | DEV_JIG_UART_ON) | ||
81 | #define DEV_T2_JIG_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \ | ||
82 | DEV_JIG_UART_OFF | DEV_JIG_UART_ON) | ||
83 | |||
84 | /* | ||
85 | * Manual Switch | ||
86 | * D- [7:5] / D+ [4:2] | ||
87 | * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO | ||
88 | */ | ||
89 | #define SW_VAUDIO ((4 << 5) | (4 << 2)) | ||
90 | #define SW_UART ((3 << 5) | (3 << 2)) | ||
91 | #define SW_AUDIO ((2 << 5) | (2 << 2)) | ||
92 | #define SW_DHOST ((1 << 5) | (1 << 2)) | ||
93 | #define SW_AUTO ((0 << 5) | (0 << 2)) | ||
94 | |||
95 | /* Interrupt 1 */ | ||
96 | #define INT_DETACH (1 << 1) | ||
97 | #define INT_ATTACH (1 << 0) | ||
98 | |||
99 | struct fsa9480_usbsw { | ||
100 | struct i2c_client *client; | ||
101 | struct fsa9480_platform_data *pdata; | ||
102 | int dev1; | ||
103 | int dev2; | ||
104 | int mansw; | ||
105 | }; | ||
106 | |||
107 | static struct fsa9480_usbsw *chip; | ||
108 | |||
109 | static int fsa9480_write_reg(struct i2c_client *client, | ||
110 | int reg, int value) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | ret = i2c_smbus_write_byte_data(client, reg, value); | ||
115 | |||
116 | if (ret < 0) | ||
117 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int fsa9480_read_reg(struct i2c_client *client, int reg) | ||
123 | { | ||
124 | int ret; | ||
125 | |||
126 | ret = i2c_smbus_read_byte_data(client, reg); | ||
127 | |||
128 | if (ret < 0) | ||
129 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
130 | |||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int fsa9480_read_irq(struct i2c_client *client, int *value) | ||
135 | { | ||
136 | int ret; | ||
137 | |||
138 | ret = i2c_smbus_read_i2c_block_data(client, | ||
139 | FSA9480_REG_INT1, 2, (u8 *)value); | ||
140 | *value &= 0xffff; | ||
141 | |||
142 | if (ret < 0) | ||
143 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | static void fsa9480_set_switch(const char *buf) | ||
149 | { | ||
150 | struct fsa9480_usbsw *usbsw = chip; | ||
151 | struct i2c_client *client = usbsw->client; | ||
152 | unsigned int value; | ||
153 | unsigned int path = 0; | ||
154 | |||
155 | value = fsa9480_read_reg(client, FSA9480_REG_CTRL); | ||
156 | |||
157 | if (!strncmp(buf, "VAUDIO", 6)) { | ||
158 | path = SW_VAUDIO; | ||
159 | value &= ~CON_MANUAL_SW; | ||
160 | } else if (!strncmp(buf, "UART", 4)) { | ||
161 | path = SW_UART; | ||
162 | value &= ~CON_MANUAL_SW; | ||
163 | } else if (!strncmp(buf, "AUDIO", 5)) { | ||
164 | path = SW_AUDIO; | ||
165 | value &= ~CON_MANUAL_SW; | ||
166 | } else if (!strncmp(buf, "DHOST", 5)) { | ||
167 | path = SW_DHOST; | ||
168 | value &= ~CON_MANUAL_SW; | ||
169 | } else if (!strncmp(buf, "AUTO", 4)) { | ||
170 | path = SW_AUTO; | ||
171 | value |= CON_MANUAL_SW; | ||
172 | } else { | ||
173 | printk(KERN_ERR "Wrong command\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | usbsw->mansw = path; | ||
178 | fsa9480_write_reg(client, FSA9480_REG_MANSW1, path); | ||
179 | fsa9480_write_reg(client, FSA9480_REG_CTRL, value); | ||
180 | } | ||
181 | |||
182 | static ssize_t fsa9480_get_switch(char *buf) | ||
183 | { | ||
184 | struct fsa9480_usbsw *usbsw = chip; | ||
185 | struct i2c_client *client = usbsw->client; | ||
186 | unsigned int value; | ||
187 | |||
188 | value = fsa9480_read_reg(client, FSA9480_REG_MANSW1); | ||
189 | |||
190 | if (value == SW_VAUDIO) | ||
191 | return sprintf(buf, "VAUDIO\n"); | ||
192 | else if (value == SW_UART) | ||
193 | return sprintf(buf, "UART\n"); | ||
194 | else if (value == SW_AUDIO) | ||
195 | return sprintf(buf, "AUDIO\n"); | ||
196 | else if (value == SW_DHOST) | ||
197 | return sprintf(buf, "DHOST\n"); | ||
198 | else if (value == SW_AUTO) | ||
199 | return sprintf(buf, "AUTO\n"); | ||
200 | else | ||
201 | return sprintf(buf, "%x", value); | ||
202 | } | ||
203 | |||
204 | static ssize_t fsa9480_show_device(struct device *dev, | ||
205 | struct device_attribute *attr, | ||
206 | char *buf) | ||
207 | { | ||
208 | struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev); | ||
209 | struct i2c_client *client = usbsw->client; | ||
210 | int dev1, dev2; | ||
211 | |||
212 | dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | ||
213 | dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | ||
214 | |||
215 | if (!dev1 && !dev2) | ||
216 | return sprintf(buf, "NONE\n"); | ||
217 | |||
218 | /* USB */ | ||
219 | if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK) | ||
220 | return sprintf(buf, "USB\n"); | ||
221 | |||
222 | /* UART */ | ||
223 | if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK) | ||
224 | return sprintf(buf, "UART\n"); | ||
225 | |||
226 | /* CHARGER */ | ||
227 | if (dev1 & DEV_T1_CHARGER_MASK) | ||
228 | return sprintf(buf, "CHARGER\n"); | ||
229 | |||
230 | /* JIG */ | ||
231 | if (dev2 & DEV_T2_JIG_MASK) | ||
232 | return sprintf(buf, "JIG\n"); | ||
233 | |||
234 | return sprintf(buf, "UNKNOWN\n"); | ||
235 | } | ||
236 | |||
237 | static ssize_t fsa9480_show_manualsw(struct device *dev, | ||
238 | struct device_attribute *attr, char *buf) | ||
239 | { | ||
240 | return fsa9480_get_switch(buf); | ||
241 | |||
242 | } | ||
243 | |||
244 | static ssize_t fsa9480_set_manualsw(struct device *dev, | ||
245 | struct device_attribute *attr, | ||
246 | const char *buf, size_t count) | ||
247 | { | ||
248 | fsa9480_set_switch(buf); | ||
249 | |||
250 | return count; | ||
251 | } | ||
252 | |||
253 | static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL); | ||
254 | static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR, | ||
255 | fsa9480_show_manualsw, fsa9480_set_manualsw); | ||
256 | |||
257 | static struct attribute *fsa9480_attributes[] = { | ||
258 | &dev_attr_device.attr, | ||
259 | &dev_attr_switch.attr, | ||
260 | NULL | ||
261 | }; | ||
262 | |||
263 | static const struct attribute_group fsa9480_group = { | ||
264 | .attrs = fsa9480_attributes, | ||
265 | }; | ||
266 | |||
267 | static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr) | ||
268 | { | ||
269 | int val1, val2, ctrl; | ||
270 | struct fsa9480_platform_data *pdata = usbsw->pdata; | ||
271 | struct i2c_client *client = usbsw->client; | ||
272 | |||
273 | val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | ||
274 | val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | ||
275 | ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL); | ||
276 | |||
277 | dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n", | ||
278 | intr, val1, val2); | ||
279 | |||
280 | if (!intr) | ||
281 | goto out; | ||
282 | |||
283 | if (intr & INT_ATTACH) { /* Attached */ | ||
284 | /* USB */ | ||
285 | if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) { | ||
286 | if (pdata->usb_cb) | ||
287 | pdata->usb_cb(FSA9480_ATTACHED); | ||
288 | |||
289 | if (usbsw->mansw) { | ||
290 | fsa9480_write_reg(client, | ||
291 | FSA9480_REG_MANSW1, usbsw->mansw); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* UART */ | ||
296 | if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) { | ||
297 | if (pdata->uart_cb) | ||
298 | pdata->uart_cb(FSA9480_ATTACHED); | ||
299 | |||
300 | if (!(ctrl & CON_MANUAL_SW)) { | ||
301 | fsa9480_write_reg(client, | ||
302 | FSA9480_REG_MANSW1, SW_UART); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* CHARGER */ | ||
307 | if (val1 & DEV_T1_CHARGER_MASK) { | ||
308 | if (pdata->charger_cb) | ||
309 | pdata->charger_cb(FSA9480_ATTACHED); | ||
310 | } | ||
311 | |||
312 | /* JIG */ | ||
313 | if (val2 & DEV_T2_JIG_MASK) { | ||
314 | if (pdata->jig_cb) | ||
315 | pdata->jig_cb(FSA9480_ATTACHED); | ||
316 | } | ||
317 | } else if (intr & INT_DETACH) { /* Detached */ | ||
318 | /* USB */ | ||
319 | if (usbsw->dev1 & DEV_T1_USB_MASK || | ||
320 | usbsw->dev2 & DEV_T2_USB_MASK) { | ||
321 | if (pdata->usb_cb) | ||
322 | pdata->usb_cb(FSA9480_DETACHED); | ||
323 | } | ||
324 | |||
325 | /* UART */ | ||
326 | if (usbsw->dev1 & DEV_T1_UART_MASK || | ||
327 | usbsw->dev2 & DEV_T2_UART_MASK) { | ||
328 | if (pdata->uart_cb) | ||
329 | pdata->uart_cb(FSA9480_DETACHED); | ||
330 | } | ||
331 | |||
332 | /* CHARGER */ | ||
333 | if (usbsw->dev1 & DEV_T1_CHARGER_MASK) { | ||
334 | if (pdata->charger_cb) | ||
335 | pdata->charger_cb(FSA9480_DETACHED); | ||
336 | } | ||
337 | |||
338 | /* JIG */ | ||
339 | if (usbsw->dev2 & DEV_T2_JIG_MASK) { | ||
340 | if (pdata->jig_cb) | ||
341 | pdata->jig_cb(FSA9480_DETACHED); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | usbsw->dev1 = val1; | ||
346 | usbsw->dev2 = val2; | ||
347 | |||
348 | out: | ||
349 | ctrl &= ~CON_INT_MASK; | ||
350 | fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); | ||
351 | } | ||
352 | |||
353 | static irqreturn_t fsa9480_irq_handler(int irq, void *data) | ||
354 | { | ||
355 | struct fsa9480_usbsw *usbsw = data; | ||
356 | struct i2c_client *client = usbsw->client; | ||
357 | int intr; | ||
358 | |||
359 | /* clear interrupt */ | ||
360 | fsa9480_read_irq(client, &intr); | ||
361 | |||
362 | /* device detection */ | ||
363 | fsa9480_detect_dev(usbsw, intr); | ||
364 | |||
365 | return IRQ_HANDLED; | ||
366 | } | ||
367 | |||
368 | static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) | ||
369 | { | ||
370 | struct fsa9480_platform_data *pdata = usbsw->pdata; | ||
371 | struct i2c_client *client = usbsw->client; | ||
372 | int ret; | ||
373 | int intr; | ||
374 | unsigned int ctrl = CON_MASK; | ||
375 | |||
376 | /* clear interrupt */ | ||
377 | fsa9480_read_irq(client, &intr); | ||
378 | |||
379 | /* unmask interrupt (attach/detach only) */ | ||
380 | fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc); | ||
381 | fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f); | ||
382 | |||
383 | usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1); | ||
384 | |||
385 | if (usbsw->mansw) | ||
386 | ctrl &= ~CON_MANUAL_SW; /* Manual Switching Mode */ | ||
387 | |||
388 | fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); | ||
389 | |||
390 | if (pdata && pdata->cfg_gpio) | ||
391 | pdata->cfg_gpio(); | ||
392 | |||
393 | if (client->irq) { | ||
394 | ret = request_threaded_irq(client->irq, NULL, | ||
395 | fsa9480_irq_handler, | ||
396 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
397 | "fsa9480 micro USB", usbsw); | ||
398 | if (ret) { | ||
399 | dev_err(&client->dev, "failed to reqeust IRQ\n"); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | device_init_wakeup(&client->dev, pdata->wakeup); | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int __devinit fsa9480_probe(struct i2c_client *client, | ||
410 | const struct i2c_device_id *id) | ||
411 | { | ||
412 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
413 | struct fsa9480_usbsw *usbsw; | ||
414 | int ret = 0; | ||
415 | |||
416 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
417 | return -EIO; | ||
418 | |||
419 | usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL); | ||
420 | if (!usbsw) { | ||
421 | dev_err(&client->dev, "failed to allocate driver data\n"); | ||
422 | return -ENOMEM; | ||
423 | } | ||
424 | |||
425 | usbsw->client = client; | ||
426 | usbsw->pdata = client->dev.platform_data; | ||
427 | |||
428 | chip = usbsw; | ||
429 | |||
430 | i2c_set_clientdata(client, usbsw); | ||
431 | |||
432 | ret = fsa9480_irq_init(usbsw); | ||
433 | if (ret) | ||
434 | goto fail1; | ||
435 | |||
436 | ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group); | ||
437 | if (ret) { | ||
438 | dev_err(&client->dev, | ||
439 | "failed to create fsa9480 attribute group\n"); | ||
440 | goto fail2; | ||
441 | } | ||
442 | |||
443 | /* ADC Detect Time: 500ms */ | ||
444 | fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6); | ||
445 | |||
446 | if (chip->pdata->reset_cb) | ||
447 | chip->pdata->reset_cb(); | ||
448 | |||
449 | /* device detection */ | ||
450 | fsa9480_detect_dev(usbsw, INT_ATTACH); | ||
451 | |||
452 | pm_runtime_set_active(&client->dev); | ||
453 | |||
454 | return 0; | ||
455 | |||
456 | fail2: | ||
457 | if (client->irq) | ||
458 | free_irq(client->irq, NULL); | ||
459 | fail1: | ||
460 | i2c_set_clientdata(client, NULL); | ||
461 | kfree(usbsw); | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | static int __devexit fsa9480_remove(struct i2c_client *client) | ||
466 | { | ||
467 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); | ||
468 | if (client->irq) | ||
469 | free_irq(client->irq, NULL); | ||
470 | i2c_set_clientdata(client, NULL); | ||
471 | |||
472 | sysfs_remove_group(&client->dev.kobj, &fsa9480_group); | ||
473 | device_init_wakeup(&client->dev, 0); | ||
474 | kfree(usbsw); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | #ifdef CONFIG_PM | ||
479 | |||
480 | static int fsa9480_suspend(struct i2c_client *client, pm_message_t state) | ||
481 | { | ||
482 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); | ||
483 | struct fsa9480_platform_data *pdata = usbsw->pdata; | ||
484 | |||
485 | if (device_may_wakeup(&client->dev) && client->irq) | ||
486 | enable_irq_wake(client->irq); | ||
487 | |||
488 | if (pdata->usb_power) | ||
489 | pdata->usb_power(0); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static int fsa9480_resume(struct i2c_client *client) | ||
495 | { | ||
496 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); | ||
497 | int dev1, dev2; | ||
498 | |||
499 | if (device_may_wakeup(&client->dev) && client->irq) | ||
500 | disable_irq_wake(client->irq); | ||
501 | |||
502 | /* | ||
503 | * Clear Pending interrupt. Note that detect_dev does what | ||
504 | * the interrupt handler does. So, we don't miss pending and | ||
505 | * we reenable interrupt if there is one. | ||
506 | */ | ||
507 | fsa9480_read_reg(client, FSA9480_REG_INT1); | ||
508 | fsa9480_read_reg(client, FSA9480_REG_INT2); | ||
509 | |||
510 | dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | ||
511 | dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | ||
512 | |||
513 | /* device detection */ | ||
514 | fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | #else | ||
520 | |||
521 | #define fsa9480_suspend NULL | ||
522 | #define fsa9480_resume NULL | ||
523 | |||
524 | #endif /* CONFIG_PM */ | ||
525 | |||
526 | static const struct i2c_device_id fsa9480_id[] = { | ||
527 | {"fsa9480", 0}, | ||
528 | {} | ||
529 | }; | ||
530 | MODULE_DEVICE_TABLE(i2c, fsa9480_id); | ||
531 | |||
532 | static struct i2c_driver fsa9480_i2c_driver = { | ||
533 | .driver = { | ||
534 | .name = "fsa9480", | ||
535 | }, | ||
536 | .probe = fsa9480_probe, | ||
537 | .remove = __devexit_p(fsa9480_remove), | ||
538 | .resume = fsa9480_resume, | ||
539 | .suspend = fsa9480_suspend, | ||
540 | .id_table = fsa9480_id, | ||
541 | }; | ||
542 | |||
543 | static int __init fsa9480_init(void) | ||
544 | { | ||
545 | return i2c_add_driver(&fsa9480_i2c_driver); | ||
546 | } | ||
547 | module_init(fsa9480_init); | ||
548 | |||
549 | static void __exit fsa9480_exit(void) | ||
550 | { | ||
551 | i2c_del_driver(&fsa9480_i2c_driver); | ||
552 | } | ||
553 | module_exit(fsa9480_exit); | ||
554 | |||
555 | MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); | ||
556 | MODULE_DESCRIPTION("FSA9480 USB Switch driver"); | ||
557 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 5fe79df44838..01eb67b4871a 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c | |||
@@ -686,6 +686,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, | |||
686 | } | 686 | } |
687 | 687 | ||
688 | if (id->driver_data == 1) { /* EG20T PCH */ | 688 | if (id->driver_data == 1) { /* EG20T PCH */ |
689 | const char *board_name; | ||
690 | |||
689 | retval = sysfs_create_file(&pdev->dev.kobj, | 691 | retval = sysfs_create_file(&pdev->dev.kobj, |
690 | &dev_attr_pch_mac.attr); | 692 | &dev_attr_pch_mac.attr); |
691 | if (retval) | 693 | if (retval) |
@@ -701,7 +703,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, | |||
701 | CLKCFG_CANCLK_MASK); | 703 | CLKCFG_CANCLK_MASK); |
702 | 704 | ||
703 | /* quirk for CM-iTC board */ | 705 | /* quirk for CM-iTC board */ |
704 | if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC")) | 706 | board_name = dmi_get_system_info(DMI_BOARD_NAME); |
707 | if (board_name && strstr(board_name, "CM-iTC")) | ||
705 | pch_phub_read_modify_write_reg(chip, | 708 | pch_phub_read_modify_write_reg(chip, |
706 | (unsigned int)CLKCFG_REG_OFFSET, | 709 | (unsigned int)CLKCFG_REG_OFFSET, |
707 | CLKCFG_UART_48MHZ | CLKCFG_BAUDDIV | | 710 | CLKCFG_UART_48MHZ | CLKCFG_BAUDDIV | |
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f091b43d00c4..89bdeaec7182 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/log2.h> | 23 | #include <linux/log2.h> |
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include <linux/suspend.h> | ||
26 | 27 | ||
27 | #include <linux/mmc/card.h> | 28 | #include <linux/mmc/card.h> |
28 | #include <linux/mmc/host.h> | 29 | #include <linux/mmc/host.h> |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 1a6937d9118f..bbf3edd85beb 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -509,15 +509,15 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, | |||
509 | struct acpi_resource_dma *p) | 509 | struct acpi_resource_dma *p) |
510 | { | 510 | { |
511 | int i; | 511 | int i; |
512 | unsigned char map = 0, flags; | 512 | unsigned char map = 0, flags = 0; |
513 | 513 | ||
514 | if (p->channel_count == 0) | 514 | if (p->channel_count == 0) |
515 | return; | 515 | flags |= IORESOURCE_DISABLED; |
516 | 516 | ||
517 | for (i = 0; i < p->channel_count; i++) | 517 | for (i = 0; i < p->channel_count; i++) |
518 | map |= 1 << p->channels[i]; | 518 | map |= 1 << p->channels[i]; |
519 | 519 | ||
520 | flags = dma_flags(dev, p->type, p->bus_master, p->transfer); | 520 | flags |= dma_flags(dev, p->type, p->bus_master, p->transfer); |
521 | pnp_register_dma_resource(dev, option_flags, map, flags); | 521 | pnp_register_dma_resource(dev, option_flags, map, flags); |
522 | } | 522 | } |
523 | 523 | ||
@@ -527,17 +527,17 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, | |||
527 | { | 527 | { |
528 | int i; | 528 | int i; |
529 | pnp_irq_mask_t map; | 529 | pnp_irq_mask_t map; |
530 | unsigned char flags; | 530 | unsigned char flags = 0; |
531 | 531 | ||
532 | if (p->interrupt_count == 0) | 532 | if (p->interrupt_count == 0) |
533 | return; | 533 | flags |= IORESOURCE_DISABLED; |
534 | 534 | ||
535 | bitmap_zero(map.bits, PNP_IRQ_NR); | 535 | bitmap_zero(map.bits, PNP_IRQ_NR); |
536 | for (i = 0; i < p->interrupt_count; i++) | 536 | for (i = 0; i < p->interrupt_count; i++) |
537 | if (p->interrupts[i]) | 537 | if (p->interrupts[i]) |
538 | __set_bit(p->interrupts[i], map.bits); | 538 | __set_bit(p->interrupts[i], map.bits); |
539 | 539 | ||
540 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 540 | flags |= irq_flags(p->triggering, p->polarity, p->sharable); |
541 | pnp_register_irq_resource(dev, option_flags, &map, flags); | 541 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
542 | } | 542 | } |
543 | 543 | ||
@@ -547,10 +547,10 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | |||
547 | { | 547 | { |
548 | int i; | 548 | int i; |
549 | pnp_irq_mask_t map; | 549 | pnp_irq_mask_t map; |
550 | unsigned char flags; | 550 | unsigned char flags = 0; |
551 | 551 | ||
552 | if (p->interrupt_count == 0) | 552 | if (p->interrupt_count == 0) |
553 | return; | 553 | flags |= IORESOURCE_DISABLED; |
554 | 554 | ||
555 | bitmap_zero(map.bits, PNP_IRQ_NR); | 555 | bitmap_zero(map.bits, PNP_IRQ_NR); |
556 | for (i = 0; i < p->interrupt_count; i++) { | 556 | for (i = 0; i < p->interrupt_count; i++) { |
@@ -564,7 +564,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | |||
564 | } | 564 | } |
565 | } | 565 | } |
566 | 566 | ||
567 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 567 | flags |= irq_flags(p->triggering, p->polarity, p->sharable); |
568 | pnp_register_irq_resource(dev, option_flags, &map, flags); | 568 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
569 | } | 569 | } |
570 | 570 | ||
@@ -575,10 +575,10 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, | |||
575 | unsigned char flags = 0; | 575 | unsigned char flags = 0; |
576 | 576 | ||
577 | if (io->address_length == 0) | 577 | if (io->address_length == 0) |
578 | return; | 578 | flags |= IORESOURCE_DISABLED; |
579 | 579 | ||
580 | if (io->io_decode == ACPI_DECODE_16) | 580 | if (io->io_decode == ACPI_DECODE_16) |
581 | flags = IORESOURCE_IO_16BIT_ADDR; | 581 | flags |= IORESOURCE_IO_16BIT_ADDR; |
582 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, | 582 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, |
583 | io->alignment, io->address_length, flags); | 583 | io->alignment, io->address_length, flags); |
584 | } | 584 | } |
@@ -587,11 +587,13 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, | |||
587 | unsigned int option_flags, | 587 | unsigned int option_flags, |
588 | struct acpi_resource_fixed_io *io) | 588 | struct acpi_resource_fixed_io *io) |
589 | { | 589 | { |
590 | unsigned char flags = 0; | ||
591 | |||
590 | if (io->address_length == 0) | 592 | if (io->address_length == 0) |
591 | return; | 593 | flags |= IORESOURCE_DISABLED; |
592 | 594 | ||
593 | pnp_register_port_resource(dev, option_flags, io->address, io->address, | 595 | pnp_register_port_resource(dev, option_flags, io->address, io->address, |
594 | 0, io->address_length, IORESOURCE_IO_FIXED); | 596 | 0, io->address_length, flags | IORESOURCE_IO_FIXED); |
595 | } | 597 | } |
596 | 598 | ||
597 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, | 599 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, |
@@ -601,10 +603,10 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, | |||
601 | unsigned char flags = 0; | 603 | unsigned char flags = 0; |
602 | 604 | ||
603 | if (p->address_length == 0) | 605 | if (p->address_length == 0) |
604 | return; | 606 | flags |= IORESOURCE_DISABLED; |
605 | 607 | ||
606 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 608 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
607 | flags = IORESOURCE_MEM_WRITEABLE; | 609 | flags |= IORESOURCE_MEM_WRITEABLE; |
608 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, | 610 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
609 | p->alignment, p->address_length, flags); | 611 | p->alignment, p->address_length, flags); |
610 | } | 612 | } |
@@ -616,10 +618,10 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, | |||
616 | unsigned char flags = 0; | 618 | unsigned char flags = 0; |
617 | 619 | ||
618 | if (p->address_length == 0) | 620 | if (p->address_length == 0) |
619 | return; | 621 | flags |= IORESOURCE_DISABLED; |
620 | 622 | ||
621 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 623 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
622 | flags = IORESOURCE_MEM_WRITEABLE; | 624 | flags |= IORESOURCE_MEM_WRITEABLE; |
623 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, | 625 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
624 | p->alignment, p->address_length, flags); | 626 | p->alignment, p->address_length, flags); |
625 | } | 627 | } |
@@ -631,10 +633,10 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, | |||
631 | unsigned char flags = 0; | 633 | unsigned char flags = 0; |
632 | 634 | ||
633 | if (p->address_length == 0) | 635 | if (p->address_length == 0) |
634 | return; | 636 | flags |= IORESOURCE_DISABLED; |
635 | 637 | ||
636 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 638 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
637 | flags = IORESOURCE_MEM_WRITEABLE; | 639 | flags |= IORESOURCE_MEM_WRITEABLE; |
638 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, | 640 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, |
639 | 0, p->address_length, flags); | 641 | 0, p->address_length, flags); |
640 | } | 642 | } |
@@ -655,18 +657,18 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, | |||
655 | } | 657 | } |
656 | 658 | ||
657 | if (p->address_length == 0) | 659 | if (p->address_length == 0) |
658 | return; | 660 | flags |= IORESOURCE_DISABLED; |
659 | 661 | ||
660 | if (p->resource_type == ACPI_MEMORY_RANGE) { | 662 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
661 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) | 663 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
662 | flags = IORESOURCE_MEM_WRITEABLE; | 664 | flags |= IORESOURCE_MEM_WRITEABLE; |
663 | pnp_register_mem_resource(dev, option_flags, p->minimum, | 665 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
664 | p->minimum, 0, p->address_length, | 666 | p->minimum, 0, p->address_length, |
665 | flags); | 667 | flags); |
666 | } else if (p->resource_type == ACPI_IO_RANGE) | 668 | } else if (p->resource_type == ACPI_IO_RANGE) |
667 | pnp_register_port_resource(dev, option_flags, p->minimum, | 669 | pnp_register_port_resource(dev, option_flags, p->minimum, |
668 | p->minimum, 0, p->address_length, | 670 | p->minimum, 0, p->address_length, |
669 | IORESOURCE_IO_FIXED); | 671 | flags | IORESOURCE_IO_FIXED); |
670 | } | 672 | } |
671 | 673 | ||
672 | static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, | 674 | static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, |
@@ -677,18 +679,18 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, | |||
677 | unsigned char flags = 0; | 679 | unsigned char flags = 0; |
678 | 680 | ||
679 | if (p->address_length == 0) | 681 | if (p->address_length == 0) |
680 | return; | 682 | flags |= IORESOURCE_DISABLED; |
681 | 683 | ||
682 | if (p->resource_type == ACPI_MEMORY_RANGE) { | 684 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
683 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) | 685 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
684 | flags = IORESOURCE_MEM_WRITEABLE; | 686 | flags |= IORESOURCE_MEM_WRITEABLE; |
685 | pnp_register_mem_resource(dev, option_flags, p->minimum, | 687 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
686 | p->minimum, 0, p->address_length, | 688 | p->minimum, 0, p->address_length, |
687 | flags); | 689 | flags); |
688 | } else if (p->resource_type == ACPI_IO_RANGE) | 690 | } else if (p->resource_type == ACPI_IO_RANGE) |
689 | pnp_register_port_resource(dev, option_flags, p->minimum, | 691 | pnp_register_port_resource(dev, option_flags, p->minimum, |
690 | p->minimum, 0, p->address_length, | 692 | p->minimum, 0, p->address_length, |
691 | IORESOURCE_IO_FIXED); | 693 | flags | IORESOURCE_IO_FIXED); |
692 | } | 694 | } |
693 | 695 | ||
694 | struct acpipnp_parse_option_s { | 696 | struct acpipnp_parse_option_s { |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index dcb61e23b985..5a538fc1cc85 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -1006,10 +1006,10 @@ config RTC_DRV_MC13XXX | |||
1006 | 1006 | ||
1007 | config RTC_DRV_MPC5121 | 1007 | config RTC_DRV_MPC5121 |
1008 | tristate "Freescale MPC5121 built-in RTC" | 1008 | tristate "Freescale MPC5121 built-in RTC" |
1009 | depends on PPC_MPC512x && RTC_CLASS | 1009 | depends on PPC_MPC512x || PPC_MPC52xx |
1010 | help | 1010 | help |
1011 | If you say yes here you will get support for the | 1011 | If you say yes here you will get support for the |
1012 | built-in RTC MPC5121. | 1012 | built-in RTC on MPC5121 or on MPC5200. |
1013 | 1013 | ||
1014 | This driver can also be built as a module. If so, the module | 1014 | This driver can also be built as a module. If so, the module |
1015 | will be called rtc-mpc5121. | 1015 | will be called rtc-mpc5121. |
@@ -1034,6 +1034,16 @@ config RTC_DRV_LPC32XX | |||
1034 | This driver can also be buillt as a module. If so, the module | 1034 | This driver can also be buillt as a module. If so, the module |
1035 | will be called rtc-lpc32xx. | 1035 | will be called rtc-lpc32xx. |
1036 | 1036 | ||
1037 | config RTC_DRV_PM8XXX | ||
1038 | tristate "Qualcomm PMIC8XXX RTC" | ||
1039 | depends on MFD_PM8XXX | ||
1040 | help | ||
1041 | If you say yes here you get support for the | ||
1042 | Qualcomm PMIC8XXX RTC. | ||
1043 | |||
1044 | To compile this driver as a module, choose M here: the | ||
1045 | module will be called rtc-pm8xxx. | ||
1046 | |||
1037 | config RTC_DRV_TEGRA | 1047 | config RTC_DRV_TEGRA |
1038 | tristate "NVIDIA Tegra Internal RTC driver" | 1048 | tristate "NVIDIA Tegra Internal RTC driver" |
1039 | depends on RTC_CLASS && ARCH_TEGRA | 1049 | depends on RTC_CLASS && ARCH_TEGRA |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0ffefe877bfa..6e6982335c10 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -77,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o | |||
77 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o | 77 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o |
78 | obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o | 78 | obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o |
79 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o | 79 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o |
80 | obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o | ||
80 | obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o | 81 | obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o |
81 | obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o | 82 | obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o |
82 | obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o | 83 | obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o |
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 09ccd8d3ba2a..da60915818b6 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2007, Domen Puncer <domen.puncer@telargo.com> | 4 | * Copyright 2007, Domen Puncer <domen.puncer@telargo.com> |
5 | * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved. | 5 | * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved. |
6 | * Copyright 2011, Dmitry Eremin-Solenikov | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -145,6 +146,55 @@ static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
145 | return 0; | 146 | return 0; |
146 | } | 147 | } |
147 | 148 | ||
149 | static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
150 | { | ||
151 | struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); | ||
152 | struct mpc5121_rtc_regs __iomem *regs = rtc->regs; | ||
153 | int tmp; | ||
154 | |||
155 | tm->tm_sec = in_8(®s->second); | ||
156 | tm->tm_min = in_8(®s->minute); | ||
157 | |||
158 | /* 12 hour format? */ | ||
159 | if (in_8(®s->hour) & 0x20) | ||
160 | tm->tm_hour = (in_8(®s->hour) >> 1) + | ||
161 | (in_8(®s->hour) & 1 ? 12 : 0); | ||
162 | else | ||
163 | tm->tm_hour = in_8(®s->hour); | ||
164 | |||
165 | tmp = in_8(®s->wday_mday); | ||
166 | tm->tm_mday = tmp & 0x1f; | ||
167 | tm->tm_mon = in_8(®s->month) - 1; | ||
168 | tm->tm_year = in_be16(®s->year) - 1900; | ||
169 | tm->tm_wday = (tmp >> 5) % 7; | ||
170 | tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); | ||
171 | tm->tm_isdst = 0; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
177 | { | ||
178 | struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); | ||
179 | struct mpc5121_rtc_regs __iomem *regs = rtc->regs; | ||
180 | |||
181 | mpc5121_rtc_update_smh(regs, tm); | ||
182 | |||
183 | /* date */ | ||
184 | out_8(®s->month_set, tm->tm_mon + 1); | ||
185 | out_8(®s->weekday_set, tm->tm_wday ? tm->tm_wday : 7); | ||
186 | out_8(®s->date_set, tm->tm_mday); | ||
187 | out_be16(®s->year_set, tm->tm_year + 1900); | ||
188 | |||
189 | /* set date sequence */ | ||
190 | out_8(®s->set_date, 0x1); | ||
191 | out_8(®s->set_date, 0x3); | ||
192 | out_8(®s->set_date, 0x1); | ||
193 | out_8(®s->set_date, 0x0); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
148 | static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | 198 | static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
149 | { | 199 | { |
150 | struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); | 200 | struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); |
@@ -248,11 +298,18 @@ static const struct rtc_class_ops mpc5121_rtc_ops = { | |||
248 | .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable, | 298 | .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable, |
249 | }; | 299 | }; |
250 | 300 | ||
301 | static const struct rtc_class_ops mpc5200_rtc_ops = { | ||
302 | .read_time = mpc5200_rtc_read_time, | ||
303 | .set_time = mpc5200_rtc_set_time, | ||
304 | .read_alarm = mpc5121_rtc_read_alarm, | ||
305 | .set_alarm = mpc5121_rtc_set_alarm, | ||
306 | .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable, | ||
307 | }; | ||
308 | |||
251 | static int __devinit mpc5121_rtc_probe(struct platform_device *op) | 309 | static int __devinit mpc5121_rtc_probe(struct platform_device *op) |
252 | { | 310 | { |
253 | struct mpc5121_rtc_data *rtc; | 311 | struct mpc5121_rtc_data *rtc; |
254 | int err = 0; | 312 | int err = 0; |
255 | u32 ka; | ||
256 | 313 | ||
257 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); | 314 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); |
258 | if (!rtc) | 315 | if (!rtc) |
@@ -287,15 +344,22 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op) | |||
287 | goto out_dispose2; | 344 | goto out_dispose2; |
288 | } | 345 | } |
289 | 346 | ||
290 | ka = in_be32(&rtc->regs->keep_alive); | 347 | if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) { |
291 | if (ka & 0x02) { | 348 | u32 ka; |
292 | dev_warn(&op->dev, | 349 | ka = in_be32(&rtc->regs->keep_alive); |
293 | "mpc5121-rtc: Battery or oscillator failure!\n"); | 350 | if (ka & 0x02) { |
294 | out_be32(&rtc->regs->keep_alive, ka); | 351 | dev_warn(&op->dev, |
352 | "mpc5121-rtc: Battery or oscillator failure!\n"); | ||
353 | out_be32(&rtc->regs->keep_alive, ka); | ||
354 | } | ||
355 | |||
356 | rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev, | ||
357 | &mpc5121_rtc_ops, THIS_MODULE); | ||
358 | } else { | ||
359 | rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev, | ||
360 | &mpc5200_rtc_ops, THIS_MODULE); | ||
295 | } | 361 | } |
296 | 362 | ||
297 | rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev, | ||
298 | &mpc5121_rtc_ops, THIS_MODULE); | ||
299 | if (IS_ERR(rtc->rtc)) { | 363 | if (IS_ERR(rtc->rtc)) { |
300 | err = PTR_ERR(rtc->rtc); | 364 | err = PTR_ERR(rtc->rtc); |
301 | goto out_free_irq; | 365 | goto out_free_irq; |
@@ -340,6 +404,7 @@ static int __devexit mpc5121_rtc_remove(struct platform_device *op) | |||
340 | 404 | ||
341 | static struct of_device_id mpc5121_rtc_match[] __devinitdata = { | 405 | static struct of_device_id mpc5121_rtc_match[] __devinitdata = { |
342 | { .compatible = "fsl,mpc5121-rtc", }, | 406 | { .compatible = "fsl,mpc5121-rtc", }, |
407 | { .compatible = "fsl,mpc5200-rtc", }, | ||
343 | {}, | 408 | {}, |
344 | }; | 409 | }; |
345 | 410 | ||
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c new file mode 100644 index 000000000000..d420e9d877e8 --- /dev/null +++ b/drivers/rtc/rtc-pm8xxx.c | |||
@@ -0,0 +1,550 @@ | |||
1 | /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/pm.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | #include <linux/mfd/pm8xxx/core.h> | ||
21 | #include <linux/mfd/pm8xxx/rtc.h> | ||
22 | |||
23 | |||
24 | /* RTC Register offsets from RTC CTRL REG */ | ||
25 | #define PM8XXX_ALARM_CTRL_OFFSET 0x01 | ||
26 | #define PM8XXX_RTC_WRITE_OFFSET 0x02 | ||
27 | #define PM8XXX_RTC_READ_OFFSET 0x06 | ||
28 | #define PM8XXX_ALARM_RW_OFFSET 0x0A | ||
29 | |||
30 | /* RTC_CTRL register bit fields */ | ||
31 | #define PM8xxx_RTC_ENABLE BIT(7) | ||
32 | #define PM8xxx_RTC_ALARM_ENABLE BIT(1) | ||
33 | #define PM8xxx_RTC_ALARM_CLEAR BIT(0) | ||
34 | |||
35 | #define NUM_8_BIT_RTC_REGS 0x4 | ||
36 | |||
37 | /** | ||
38 | * struct pm8xxx_rtc - rtc driver internal structure | ||
39 | * @rtc: rtc device for this driver. | ||
40 | * @rtc_alarm_irq: rtc alarm irq number. | ||
41 | * @rtc_base: address of rtc control register. | ||
42 | * @rtc_read_base: base address of read registers. | ||
43 | * @rtc_write_base: base address of write registers. | ||
44 | * @alarm_rw_base: base address of alarm registers. | ||
45 | * @ctrl_reg: rtc control register. | ||
46 | * @rtc_dev: device structure. | ||
47 | * @ctrl_reg_lock: spinlock protecting access to ctrl_reg. | ||
48 | */ | ||
49 | struct pm8xxx_rtc { | ||
50 | struct rtc_device *rtc; | ||
51 | int rtc_alarm_irq; | ||
52 | int rtc_base; | ||
53 | int rtc_read_base; | ||
54 | int rtc_write_base; | ||
55 | int alarm_rw_base; | ||
56 | u8 ctrl_reg; | ||
57 | struct device *rtc_dev; | ||
58 | spinlock_t ctrl_reg_lock; | ||
59 | }; | ||
60 | |||
61 | /* | ||
62 | * The RTC registers need to be read/written one byte at a time. This is a | ||
63 | * hardware limitation. | ||
64 | */ | ||
65 | static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, | ||
66 | int base, int count) | ||
67 | { | ||
68 | int i, rc; | ||
69 | struct device *parent = rtc_dd->rtc_dev->parent; | ||
70 | |||
71 | for (i = 0; i < count; i++) { | ||
72 | rc = pm8xxx_readb(parent, base + i, &rtc_val[i]); | ||
73 | if (rc < 0) { | ||
74 | dev_err(rtc_dd->rtc_dev, "PMIC read failed\n"); | ||
75 | return rc; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, | ||
83 | int base, int count) | ||
84 | { | ||
85 | int i, rc; | ||
86 | struct device *parent = rtc_dd->rtc_dev->parent; | ||
87 | |||
88 | for (i = 0; i < count; i++) { | ||
89 | rc = pm8xxx_writeb(parent, base + i, rtc_val[i]); | ||
90 | if (rc < 0) { | ||
91 | dev_err(rtc_dd->rtc_dev, "PMIC write failed\n"); | ||
92 | return rc; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Steps to write the RTC registers. | ||
101 | * 1. Disable alarm if enabled. | ||
102 | * 2. Write 0x00 to LSB. | ||
103 | * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0]. | ||
104 | * 4. Enable alarm if disabled in step 1. | ||
105 | */ | ||
106 | static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
107 | { | ||
108 | int rc, i; | ||
109 | unsigned long secs, irq_flags; | ||
110 | u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg; | ||
111 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
112 | |||
113 | rtc_tm_to_time(tm, &secs); | ||
114 | |||
115 | for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { | ||
116 | value[i] = secs & 0xFF; | ||
117 | secs >>= 8; | ||
118 | } | ||
119 | |||
120 | dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); | ||
121 | |||
122 | spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
123 | ctrl_reg = rtc_dd->ctrl_reg; | ||
124 | |||
125 | if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) { | ||
126 | alarm_enabled = 1; | ||
127 | ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; | ||
128 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, | ||
129 | 1); | ||
130 | if (rc < 0) { | ||
131 | dev_err(dev, "Write to RTC control register " | ||
132 | "failed\n"); | ||
133 | goto rtc_rw_fail; | ||
134 | } | ||
135 | rtc_dd->ctrl_reg = ctrl_reg; | ||
136 | } else | ||
137 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
138 | |||
139 | /* Write 0 to Byte[0] */ | ||
140 | reg = 0; | ||
141 | rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_write_base, 1); | ||
142 | if (rc < 0) { | ||
143 | dev_err(dev, "Write to RTC write data register failed\n"); | ||
144 | goto rtc_rw_fail; | ||
145 | } | ||
146 | |||
147 | /* Write Byte[1], Byte[2], Byte[3] */ | ||
148 | rc = pm8xxx_write_wrapper(rtc_dd, value + 1, | ||
149 | rtc_dd->rtc_write_base + 1, 3); | ||
150 | if (rc < 0) { | ||
151 | dev_err(dev, "Write to RTC write data register failed\n"); | ||
152 | goto rtc_rw_fail; | ||
153 | } | ||
154 | |||
155 | /* Write Byte[0] */ | ||
156 | rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1); | ||
157 | if (rc < 0) { | ||
158 | dev_err(dev, "Write to RTC write data register failed\n"); | ||
159 | goto rtc_rw_fail; | ||
160 | } | ||
161 | |||
162 | if (alarm_enabled) { | ||
163 | ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; | ||
164 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, | ||
165 | 1); | ||
166 | if (rc < 0) { | ||
167 | dev_err(dev, "Write to RTC control register " | ||
168 | "failed\n"); | ||
169 | goto rtc_rw_fail; | ||
170 | } | ||
171 | rtc_dd->ctrl_reg = ctrl_reg; | ||
172 | } | ||
173 | |||
174 | rtc_rw_fail: | ||
175 | if (alarm_enabled) | ||
176 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
177 | |||
178 | return rc; | ||
179 | } | ||
180 | |||
181 | static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
182 | { | ||
183 | int rc; | ||
184 | u8 value[NUM_8_BIT_RTC_REGS], reg; | ||
185 | unsigned long secs; | ||
186 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
187 | |||
188 | rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base, | ||
189 | NUM_8_BIT_RTC_REGS); | ||
190 | if (rc < 0) { | ||
191 | dev_err(dev, "RTC read data register failed\n"); | ||
192 | return rc; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Read the LSB again and check if there has been a carry over. | ||
197 | * If there is, redo the read operation. | ||
198 | */ | ||
199 | rc = pm8xxx_read_wrapper(rtc_dd, ®, rtc_dd->rtc_read_base, 1); | ||
200 | if (rc < 0) { | ||
201 | dev_err(dev, "RTC read data register failed\n"); | ||
202 | return rc; | ||
203 | } | ||
204 | |||
205 | if (unlikely(reg < value[0])) { | ||
206 | rc = pm8xxx_read_wrapper(rtc_dd, value, | ||
207 | rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS); | ||
208 | if (rc < 0) { | ||
209 | dev_err(dev, "RTC read data register failed\n"); | ||
210 | return rc; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); | ||
215 | |||
216 | rtc_time_to_tm(secs, tm); | ||
217 | |||
218 | rc = rtc_valid_tm(tm); | ||
219 | if (rc < 0) { | ||
220 | dev_err(dev, "Invalid time read from RTC\n"); | ||
221 | return rc; | ||
222 | } | ||
223 | |||
224 | dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", | ||
225 | secs, tm->tm_hour, tm->tm_min, tm->tm_sec, | ||
226 | tm->tm_mday, tm->tm_mon, tm->tm_year); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
232 | { | ||
233 | int rc, i; | ||
234 | u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg; | ||
235 | unsigned long secs, irq_flags; | ||
236 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
237 | |||
238 | rtc_tm_to_time(&alarm->time, &secs); | ||
239 | |||
240 | for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { | ||
241 | value[i] = secs & 0xFF; | ||
242 | secs >>= 8; | ||
243 | } | ||
244 | |||
245 | spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
246 | |||
247 | rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, | ||
248 | NUM_8_BIT_RTC_REGS); | ||
249 | if (rc < 0) { | ||
250 | dev_err(dev, "Write to RTC ALARM register failed\n"); | ||
251 | goto rtc_rw_fail; | ||
252 | } | ||
253 | |||
254 | ctrl_reg = rtc_dd->ctrl_reg; | ||
255 | ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : | ||
256 | (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); | ||
257 | |||
258 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); | ||
259 | if (rc < 0) { | ||
260 | dev_err(dev, "Write to RTC control register failed\n"); | ||
261 | goto rtc_rw_fail; | ||
262 | } | ||
263 | |||
264 | rtc_dd->ctrl_reg = ctrl_reg; | ||
265 | |||
266 | dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", | ||
267 | alarm->time.tm_hour, alarm->time.tm_min, | ||
268 | alarm->time.tm_sec, alarm->time.tm_mday, | ||
269 | alarm->time.tm_mon, alarm->time.tm_year); | ||
270 | rtc_rw_fail: | ||
271 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
272 | return rc; | ||
273 | } | ||
274 | |||
275 | static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
276 | { | ||
277 | int rc; | ||
278 | u8 value[NUM_8_BIT_RTC_REGS]; | ||
279 | unsigned long secs; | ||
280 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
281 | |||
282 | rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, | ||
283 | NUM_8_BIT_RTC_REGS); | ||
284 | if (rc < 0) { | ||
285 | dev_err(dev, "RTC alarm time read failed\n"); | ||
286 | return rc; | ||
287 | } | ||
288 | |||
289 | secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); | ||
290 | |||
291 | rtc_time_to_tm(secs, &alarm->time); | ||
292 | |||
293 | rc = rtc_valid_tm(&alarm->time); | ||
294 | if (rc < 0) { | ||
295 | dev_err(dev, "Invalid alarm time read from RTC\n"); | ||
296 | return rc; | ||
297 | } | ||
298 | |||
299 | dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", | ||
300 | alarm->time.tm_hour, alarm->time.tm_min, | ||
301 | alarm->time.tm_sec, alarm->time.tm_mday, | ||
302 | alarm->time.tm_mon, alarm->time.tm_year); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) | ||
308 | { | ||
309 | int rc; | ||
310 | unsigned long irq_flags; | ||
311 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
312 | u8 ctrl_reg; | ||
313 | |||
314 | spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
315 | ctrl_reg = rtc_dd->ctrl_reg; | ||
316 | ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : | ||
317 | (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); | ||
318 | |||
319 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); | ||
320 | if (rc < 0) { | ||
321 | dev_err(dev, "Write to RTC control register failed\n"); | ||
322 | goto rtc_rw_fail; | ||
323 | } | ||
324 | |||
325 | rtc_dd->ctrl_reg = ctrl_reg; | ||
326 | |||
327 | rtc_rw_fail: | ||
328 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
329 | return rc; | ||
330 | } | ||
331 | |||
332 | static struct rtc_class_ops pm8xxx_rtc_ops = { | ||
333 | .read_time = pm8xxx_rtc_read_time, | ||
334 | .set_alarm = pm8xxx_rtc_set_alarm, | ||
335 | .read_alarm = pm8xxx_rtc_read_alarm, | ||
336 | .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, | ||
337 | }; | ||
338 | |||
339 | static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) | ||
340 | { | ||
341 | struct pm8xxx_rtc *rtc_dd = dev_id; | ||
342 | u8 ctrl_reg; | ||
343 | int rc; | ||
344 | unsigned long irq_flags; | ||
345 | |||
346 | rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF); | ||
347 | |||
348 | spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
349 | |||
350 | /* Clear the alarm enable bit */ | ||
351 | ctrl_reg = rtc_dd->ctrl_reg; | ||
352 | ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; | ||
353 | |||
354 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); | ||
355 | if (rc < 0) { | ||
356 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
357 | dev_err(rtc_dd->rtc_dev, "Write to RTC control register " | ||
358 | "failed\n"); | ||
359 | goto rtc_alarm_handled; | ||
360 | } | ||
361 | |||
362 | rtc_dd->ctrl_reg = ctrl_reg; | ||
363 | spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); | ||
364 | |||
365 | /* Clear RTC alarm register */ | ||
366 | rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + | ||
367 | PM8XXX_ALARM_CTRL_OFFSET, 1); | ||
368 | if (rc < 0) { | ||
369 | dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read " | ||
370 | "failed\n"); | ||
371 | goto rtc_alarm_handled; | ||
372 | } | ||
373 | |||
374 | ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR; | ||
375 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + | ||
376 | PM8XXX_ALARM_CTRL_OFFSET, 1); | ||
377 | if (rc < 0) | ||
378 | dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register" | ||
379 | " failed\n"); | ||
380 | |||
381 | rtc_alarm_handled: | ||
382 | return IRQ_HANDLED; | ||
383 | } | ||
384 | |||
385 | static int __devinit pm8xxx_rtc_probe(struct platform_device *pdev) | ||
386 | { | ||
387 | int rc; | ||
388 | u8 ctrl_reg; | ||
389 | bool rtc_write_enable = false; | ||
390 | struct pm8xxx_rtc *rtc_dd; | ||
391 | struct resource *rtc_resource; | ||
392 | const struct pm8xxx_rtc_platform_data *pdata = | ||
393 | dev_get_platdata(&pdev->dev); | ||
394 | |||
395 | if (pdata != NULL) | ||
396 | rtc_write_enable = pdata->rtc_write_enable; | ||
397 | |||
398 | rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL); | ||
399 | if (rtc_dd == NULL) { | ||
400 | dev_err(&pdev->dev, "Unable to allocate memory!\n"); | ||
401 | return -ENOMEM; | ||
402 | } | ||
403 | |||
404 | /* Initialise spinlock to protect RTC control register */ | ||
405 | spin_lock_init(&rtc_dd->ctrl_reg_lock); | ||
406 | |||
407 | rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0); | ||
408 | if (rtc_dd->rtc_alarm_irq < 0) { | ||
409 | dev_err(&pdev->dev, "Alarm IRQ resource absent!\n"); | ||
410 | rc = -ENXIO; | ||
411 | goto fail_rtc_enable; | ||
412 | } | ||
413 | |||
414 | rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO, | ||
415 | "pmic_rtc_base"); | ||
416 | if (!(rtc_resource && rtc_resource->start)) { | ||
417 | dev_err(&pdev->dev, "RTC IO resource absent!\n"); | ||
418 | rc = -ENXIO; | ||
419 | goto fail_rtc_enable; | ||
420 | } | ||
421 | |||
422 | rtc_dd->rtc_base = rtc_resource->start; | ||
423 | |||
424 | /* Setup RTC register addresses */ | ||
425 | rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET; | ||
426 | rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET; | ||
427 | rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET; | ||
428 | |||
429 | rtc_dd->rtc_dev = &pdev->dev; | ||
430 | |||
431 | /* Check if the RTC is on, else turn it on */ | ||
432 | rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); | ||
433 | if (rc < 0) { | ||
434 | dev_err(&pdev->dev, "RTC control register read failed!\n"); | ||
435 | goto fail_rtc_enable; | ||
436 | } | ||
437 | |||
438 | if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) { | ||
439 | ctrl_reg |= PM8xxx_RTC_ENABLE; | ||
440 | rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, | ||
441 | 1); | ||
442 | if (rc < 0) { | ||
443 | dev_err(&pdev->dev, "Write to RTC control register " | ||
444 | "failed\n"); | ||
445 | goto fail_rtc_enable; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | rtc_dd->ctrl_reg = ctrl_reg; | ||
450 | if (rtc_write_enable == true) | ||
451 | pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time; | ||
452 | |||
453 | platform_set_drvdata(pdev, rtc_dd); | ||
454 | |||
455 | /* Register the RTC device */ | ||
456 | rtc_dd->rtc = rtc_device_register("pm8xxx_rtc", &pdev->dev, | ||
457 | &pm8xxx_rtc_ops, THIS_MODULE); | ||
458 | if (IS_ERR(rtc_dd->rtc)) { | ||
459 | dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n", | ||
460 | __func__, PTR_ERR(rtc_dd->rtc)); | ||
461 | rc = PTR_ERR(rtc_dd->rtc); | ||
462 | goto fail_rtc_enable; | ||
463 | } | ||
464 | |||
465 | /* Request the alarm IRQ */ | ||
466 | rc = request_any_context_irq(rtc_dd->rtc_alarm_irq, | ||
467 | pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, | ||
468 | "pm8xxx_rtc_alarm", rtc_dd); | ||
469 | if (rc < 0) { | ||
470 | dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc); | ||
471 | goto fail_req_irq; | ||
472 | } | ||
473 | |||
474 | device_init_wakeup(&pdev->dev, 1); | ||
475 | |||
476 | dev_dbg(&pdev->dev, "Probe success !!\n"); | ||
477 | |||
478 | return 0; | ||
479 | |||
480 | fail_req_irq: | ||
481 | rtc_device_unregister(rtc_dd->rtc); | ||
482 | fail_rtc_enable: | ||
483 | platform_set_drvdata(pdev, NULL); | ||
484 | kfree(rtc_dd); | ||
485 | return rc; | ||
486 | } | ||
487 | |||
488 | static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev) | ||
489 | { | ||
490 | struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev); | ||
491 | |||
492 | device_init_wakeup(&pdev->dev, 0); | ||
493 | free_irq(rtc_dd->rtc_alarm_irq, rtc_dd); | ||
494 | rtc_device_unregister(rtc_dd->rtc); | ||
495 | platform_set_drvdata(pdev, NULL); | ||
496 | kfree(rtc_dd); | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | #ifdef CONFIG_PM_SLEEP | ||
502 | static int pm8xxx_rtc_resume(struct device *dev) | ||
503 | { | ||
504 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
505 | |||
506 | if (device_may_wakeup(dev)) | ||
507 | disable_irq_wake(rtc_dd->rtc_alarm_irq); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int pm8xxx_rtc_suspend(struct device *dev) | ||
513 | { | ||
514 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | ||
515 | |||
516 | if (device_may_wakeup(dev)) | ||
517 | enable_irq_wake(rtc_dd->rtc_alarm_irq); | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | #endif | ||
522 | |||
523 | SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume); | ||
524 | |||
525 | static struct platform_driver pm8xxx_rtc_driver = { | ||
526 | .probe = pm8xxx_rtc_probe, | ||
527 | .remove = __devexit_p(pm8xxx_rtc_remove), | ||
528 | .driver = { | ||
529 | .name = PM8XXX_RTC_DEV_NAME, | ||
530 | .owner = THIS_MODULE, | ||
531 | .pm = &pm8xxx_rtc_pm_ops, | ||
532 | }, | ||
533 | }; | ||
534 | |||
535 | static int __init pm8xxx_rtc_init(void) | ||
536 | { | ||
537 | return platform_driver_register(&pm8xxx_rtc_driver); | ||
538 | } | ||
539 | module_init(pm8xxx_rtc_init); | ||
540 | |||
541 | static void __exit pm8xxx_rtc_exit(void) | ||
542 | { | ||
543 | platform_driver_unregister(&pm8xxx_rtc_driver); | ||
544 | } | ||
545 | module_exit(pm8xxx_rtc_exit); | ||
546 | |||
547 | MODULE_ALIAS("platform:rtc-pm8xxx"); | ||
548 | MODULE_DESCRIPTION("PMIC8xxx RTC driver"); | ||
549 | MODULE_LICENSE("GPL v2"); | ||
550 | MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>"); | ||
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2a65e85e0f56..9329dbb9ebab 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -57,11 +57,13 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) | |||
57 | { | 57 | { |
58 | struct rtc_device *rdev = id; | 58 | struct rtc_device *rdev = id; |
59 | 59 | ||
60 | clk_enable(rtc_clk); | ||
60 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); | 61 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); |
61 | 62 | ||
62 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 63 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
63 | writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); | 64 | writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); |
64 | 65 | ||
66 | clk_disable(rtc_clk); | ||
65 | return IRQ_HANDLED; | 67 | return IRQ_HANDLED; |
66 | } | 68 | } |
67 | 69 | ||
@@ -69,11 +71,13 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) | |||
69 | { | 71 | { |
70 | struct rtc_device *rdev = id; | 72 | struct rtc_device *rdev = id; |
71 | 73 | ||
74 | clk_enable(rtc_clk); | ||
72 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); | 75 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); |
73 | 76 | ||
74 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 77 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
75 | writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); | 78 | writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); |
76 | 79 | ||
80 | clk_disable(rtc_clk); | ||
77 | return IRQ_HANDLED; | 81 | return IRQ_HANDLED; |
78 | } | 82 | } |
79 | 83 | ||
@@ -84,12 +88,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) | |||
84 | 88 | ||
85 | pr_debug("%s: aie=%d\n", __func__, enabled); | 89 | pr_debug("%s: aie=%d\n", __func__, enabled); |
86 | 90 | ||
91 | clk_enable(rtc_clk); | ||
87 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; | 92 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; |
88 | 93 | ||
89 | if (enabled) | 94 | if (enabled) |
90 | tmp |= S3C2410_RTCALM_ALMEN; | 95 | tmp |= S3C2410_RTCALM_ALMEN; |
91 | 96 | ||
92 | writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); | 97 | writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); |
98 | clk_disable(rtc_clk); | ||
93 | 99 | ||
94 | return 0; | 100 | return 0; |
95 | } | 101 | } |
@@ -103,6 +109,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
103 | if (!is_power_of_2(freq)) | 109 | if (!is_power_of_2(freq)) |
104 | return -EINVAL; | 110 | return -EINVAL; |
105 | 111 | ||
112 | clk_enable(rtc_clk); | ||
106 | spin_lock_irq(&s3c_rtc_pie_lock); | 113 | spin_lock_irq(&s3c_rtc_pie_lock); |
107 | 114 | ||
108 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { | 115 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { |
@@ -114,6 +121,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
114 | 121 | ||
115 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); | 122 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); |
116 | spin_unlock_irq(&s3c_rtc_pie_lock); | 123 | spin_unlock_irq(&s3c_rtc_pie_lock); |
124 | clk_disable(rtc_clk); | ||
117 | 125 | ||
118 | return 0; | 126 | return 0; |
119 | } | 127 | } |
@@ -125,6 +133,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | |||
125 | unsigned int have_retried = 0; | 133 | unsigned int have_retried = 0; |
126 | void __iomem *base = s3c_rtc_base; | 134 | void __iomem *base = s3c_rtc_base; |
127 | 135 | ||
136 | clk_enable(rtc_clk); | ||
128 | retry_get_time: | 137 | retry_get_time: |
129 | rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); | 138 | rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); |
130 | rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); | 139 | rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); |
@@ -157,6 +166,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | |||
157 | rtc_tm->tm_year += 100; | 166 | rtc_tm->tm_year += 100; |
158 | rtc_tm->tm_mon -= 1; | 167 | rtc_tm->tm_mon -= 1; |
159 | 168 | ||
169 | clk_disable(rtc_clk); | ||
160 | return rtc_valid_tm(rtc_tm); | 170 | return rtc_valid_tm(rtc_tm); |
161 | } | 171 | } |
162 | 172 | ||
@@ -165,6 +175,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) | |||
165 | void __iomem *base = s3c_rtc_base; | 175 | void __iomem *base = s3c_rtc_base; |
166 | int year = tm->tm_year - 100; | 176 | int year = tm->tm_year - 100; |
167 | 177 | ||
178 | clk_enable(rtc_clk); | ||
168 | pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", | 179 | pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", |
169 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | 180 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
170 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 181 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
@@ -182,6 +193,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) | |||
182 | writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE); | 193 | writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE); |
183 | writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON); | 194 | writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON); |
184 | writeb(bin2bcd(year), base + S3C2410_RTCYEAR); | 195 | writeb(bin2bcd(year), base + S3C2410_RTCYEAR); |
196 | clk_disable(rtc_clk); | ||
185 | 197 | ||
186 | return 0; | 198 | return 0; |
187 | } | 199 | } |
@@ -192,6 +204,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
192 | void __iomem *base = s3c_rtc_base; | 204 | void __iomem *base = s3c_rtc_base; |
193 | unsigned int alm_en; | 205 | unsigned int alm_en; |
194 | 206 | ||
207 | clk_enable(rtc_clk); | ||
195 | alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); | 208 | alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); |
196 | alm_tm->tm_min = readb(base + S3C2410_ALMMIN); | 209 | alm_tm->tm_min = readb(base + S3C2410_ALMMIN); |
197 | alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); | 210 | alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); |
@@ -243,6 +256,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
243 | else | 256 | else |
244 | alm_tm->tm_year = -1; | 257 | alm_tm->tm_year = -1; |
245 | 258 | ||
259 | clk_disable(rtc_clk); | ||
246 | return 0; | 260 | return 0; |
247 | } | 261 | } |
248 | 262 | ||
@@ -252,6 +266,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
252 | void __iomem *base = s3c_rtc_base; | 266 | void __iomem *base = s3c_rtc_base; |
253 | unsigned int alrm_en; | 267 | unsigned int alrm_en; |
254 | 268 | ||
269 | clk_enable(rtc_clk); | ||
255 | pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", | 270 | pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", |
256 | alrm->enabled, | 271 | alrm->enabled, |
257 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | 272 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
@@ -282,6 +297,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
282 | 297 | ||
283 | s3c_rtc_setaie(dev, alrm->enabled); | 298 | s3c_rtc_setaie(dev, alrm->enabled); |
284 | 299 | ||
300 | clk_disable(rtc_clk); | ||
285 | return 0; | 301 | return 0; |
286 | } | 302 | } |
287 | 303 | ||
@@ -289,6 +305,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | |||
289 | { | 305 | { |
290 | unsigned int ticnt; | 306 | unsigned int ticnt; |
291 | 307 | ||
308 | clk_enable(rtc_clk); | ||
292 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { | 309 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
293 | ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); | 310 | ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); |
294 | ticnt &= S3C64XX_RTCCON_TICEN; | 311 | ticnt &= S3C64XX_RTCCON_TICEN; |
@@ -298,6 +315,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | |||
298 | } | 315 | } |
299 | 316 | ||
300 | seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); | 317 | seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); |
318 | clk_disable(rtc_clk); | ||
301 | return 0; | 319 | return 0; |
302 | } | 320 | } |
303 | 321 | ||
@@ -360,6 +378,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
360 | if (s3c_rtc_base == NULL) | 378 | if (s3c_rtc_base == NULL) |
361 | return; | 379 | return; |
362 | 380 | ||
381 | clk_enable(rtc_clk); | ||
363 | if (!en) { | 382 | if (!en) { |
364 | tmp = readw(base + S3C2410_RTCCON); | 383 | tmp = readw(base + S3C2410_RTCCON); |
365 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 384 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
@@ -399,6 +418,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
399 | base + S3C2410_RTCCON); | 418 | base + S3C2410_RTCCON); |
400 | } | 419 | } |
401 | } | 420 | } |
421 | clk_disable(rtc_clk); | ||
402 | } | 422 | } |
403 | 423 | ||
404 | static int __devexit s3c_rtc_remove(struct platform_device *dev) | 424 | static int __devexit s3c_rtc_remove(struct platform_device *dev) |
@@ -410,7 +430,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) | |||
410 | 430 | ||
411 | s3c_rtc_setaie(&dev->dev, 0); | 431 | s3c_rtc_setaie(&dev->dev, 0); |
412 | 432 | ||
413 | clk_disable(rtc_clk); | ||
414 | clk_put(rtc_clk); | 433 | clk_put(rtc_clk); |
415 | rtc_clk = NULL; | 434 | rtc_clk = NULL; |
416 | 435 | ||
@@ -529,6 +548,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
529 | 548 | ||
530 | s3c_rtc_setfreq(&pdev->dev, 1); | 549 | s3c_rtc_setfreq(&pdev->dev, 1); |
531 | 550 | ||
551 | clk_disable(rtc_clk); | ||
552 | |||
532 | return 0; | 553 | return 0; |
533 | 554 | ||
534 | err_nortc: | 555 | err_nortc: |
@@ -554,6 +575,7 @@ static int ticnt_save, ticnt_en_save; | |||
554 | 575 | ||
555 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 576 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) |
556 | { | 577 | { |
578 | clk_enable(rtc_clk); | ||
557 | /* save TICNT for anyone using periodic interrupts */ | 579 | /* save TICNT for anyone using periodic interrupts */ |
558 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); | 580 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); |
559 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { | 581 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
@@ -568,6 +590,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
568 | else | 590 | else |
569 | dev_err(&pdev->dev, "enable_irq_wake failed\n"); | 591 | dev_err(&pdev->dev, "enable_irq_wake failed\n"); |
570 | } | 592 | } |
593 | clk_disable(rtc_clk); | ||
571 | 594 | ||
572 | return 0; | 595 | return 0; |
573 | } | 596 | } |
@@ -576,6 +599,7 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
576 | { | 599 | { |
577 | unsigned int tmp; | 600 | unsigned int tmp; |
578 | 601 | ||
602 | clk_enable(rtc_clk); | ||
579 | s3c_rtc_enable(pdev, 1); | 603 | s3c_rtc_enable(pdev, 1); |
580 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); | 604 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); |
581 | if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { | 605 | if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { |
@@ -587,6 +611,7 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
587 | disable_irq_wake(s3c_rtc_alarmno); | 611 | disable_irq_wake(s3c_rtc_alarmno); |
588 | wake_en = false; | 612 | wake_en = false; |
589 | } | 613 | } |
614 | clk_disable(rtc_clk); | ||
590 | 615 | ||
591 | return 0; | 616 | return 0; |
592 | } | 617 | } |
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 2fc31aac3f4e..75259fe38602 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c | |||
@@ -343,7 +343,7 @@ static int __devinit tegra_rtc_probe(struct platform_device *pdev) | |||
343 | 343 | ||
344 | /* set context info. */ | 344 | /* set context info. */ |
345 | info->pdev = pdev; | 345 | info->pdev = pdev; |
346 | info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock); | 346 | spin_lock_init(&info->tegra_rtc_lock); |
347 | 347 | ||
348 | platform_set_drvdata(pdev, info); | 348 | platform_set_drvdata(pdev, info); |
349 | 349 | ||
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index f9a2799c44d6..9a81f778d6b2 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c | |||
@@ -275,7 +275,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
275 | goto out; | 275 | goto out; |
276 | 276 | ||
277 | save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; | 277 | save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; |
278 | twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | 278 | ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); |
279 | if (ret < 0) | 279 | if (ret < 0) |
280 | goto out; | 280 | goto out; |
281 | 281 | ||
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2d93c8d61ad5..1e54b8b7f698 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -117,6 +117,14 @@ config LCD_LD9040 | |||
117 | If you have an LD9040 Panel, say Y to enable its | 117 | If you have an LD9040 Panel, say Y to enable its |
118 | control driver. | 118 | control driver. |
119 | 119 | ||
120 | config LCD_AMS369FG06 | ||
121 | tristate "AMS369FG06 AMOLED LCD Driver" | ||
122 | depends on SPI && BACKLIGHT_CLASS_DEVICE | ||
123 | default n | ||
124 | help | ||
125 | If you have an AMS369FG06 AMOLED Panel, say Y to enable its | ||
126 | LCD control driver. | ||
127 | |||
120 | endif # LCD_CLASS_DEVICE | 128 | endif # LCD_CLASS_DEVICE |
121 | 129 | ||
122 | # | 130 | # |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index ee72adb8786e..bf1dd92b7527 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_TDO24M) += tdo24m.o | |||
13 | obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o | 13 | obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o |
14 | obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o | 14 | obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o |
15 | obj-$(CONFIG_LCD_LD9040) += ld9040.o | 15 | obj-$(CONFIG_LCD_LD9040) += ld9040.o |
16 | obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o | ||
16 | 17 | ||
17 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 18 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
18 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | 19 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o |
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index d2a96a421ffd..183b6f639852 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c | |||
@@ -722,8 +722,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, | |||
722 | goto out2; | 722 | goto out2; |
723 | } | 723 | } |
724 | 724 | ||
725 | bl->props.max_brightness = | 725 | bl->props.brightness = ADP8860_MAX_BRIGHTNESS; |
726 | bl->props.brightness = ADP8860_MAX_BRIGHTNESS; | ||
727 | 726 | ||
728 | data->bl = bl; | 727 | data->bl = bl; |
729 | 728 | ||
diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c new file mode 100644 index 000000000000..9f0a491e2a05 --- /dev/null +++ b/drivers/video/backlight/ams369fg06.c | |||
@@ -0,0 +1,646 @@ | |||
1 | /* | ||
2 | * ams369fg06 AMOLED LCD panel driver. | ||
3 | * | ||
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * Derived from drivers/video/s6e63m0.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
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 | */ | ||
23 | |||
24 | #include <linux/wait.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/lcd.h> | ||
30 | #include <linux/backlight.h> | ||
31 | |||
32 | #define SLEEPMSEC 0x1000 | ||
33 | #define ENDDEF 0x2000 | ||
34 | #define DEFMASK 0xFF00 | ||
35 | #define COMMAND_ONLY 0xFE | ||
36 | #define DATA_ONLY 0xFF | ||
37 | |||
38 | #define MAX_GAMMA_LEVEL 5 | ||
39 | #define GAMMA_TABLE_COUNT 21 | ||
40 | |||
41 | #define MIN_BRIGHTNESS 0 | ||
42 | #define MAX_BRIGHTNESS 255 | ||
43 | #define DEFAULT_BRIGHTNESS 150 | ||
44 | |||
45 | struct ams369fg06 { | ||
46 | struct device *dev; | ||
47 | struct spi_device *spi; | ||
48 | unsigned int power; | ||
49 | struct lcd_device *ld; | ||
50 | struct backlight_device *bd; | ||
51 | struct lcd_platform_data *lcd_pd; | ||
52 | }; | ||
53 | |||
54 | static const unsigned short seq_display_on[] = { | ||
55 | 0x14, 0x03, | ||
56 | ENDDEF, 0x0000 | ||
57 | }; | ||
58 | |||
59 | static const unsigned short seq_display_off[] = { | ||
60 | 0x14, 0x00, | ||
61 | ENDDEF, 0x0000 | ||
62 | }; | ||
63 | |||
64 | static const unsigned short seq_stand_by_on[] = { | ||
65 | 0x1D, 0xA1, | ||
66 | SLEEPMSEC, 200, | ||
67 | ENDDEF, 0x0000 | ||
68 | }; | ||
69 | |||
70 | static const unsigned short seq_stand_by_off[] = { | ||
71 | 0x1D, 0xA0, | ||
72 | SLEEPMSEC, 250, | ||
73 | ENDDEF, 0x0000 | ||
74 | }; | ||
75 | |||
76 | static const unsigned short seq_setting[] = { | ||
77 | 0x31, 0x08, | ||
78 | 0x32, 0x14, | ||
79 | 0x30, 0x02, | ||
80 | 0x27, 0x01, | ||
81 | 0x12, 0x08, | ||
82 | 0x13, 0x08, | ||
83 | 0x15, 0x00, | ||
84 | 0x16, 0x00, | ||
85 | |||
86 | 0xef, 0xd0, | ||
87 | DATA_ONLY, 0xe8, | ||
88 | |||
89 | 0x39, 0x44, | ||
90 | 0x40, 0x00, | ||
91 | 0x41, 0x3f, | ||
92 | 0x42, 0x2a, | ||
93 | 0x43, 0x27, | ||
94 | 0x44, 0x27, | ||
95 | 0x45, 0x1f, | ||
96 | 0x46, 0x44, | ||
97 | 0x50, 0x00, | ||
98 | 0x51, 0x00, | ||
99 | 0x52, 0x17, | ||
100 | 0x53, 0x24, | ||
101 | 0x54, 0x26, | ||
102 | 0x55, 0x1f, | ||
103 | 0x56, 0x43, | ||
104 | 0x60, 0x00, | ||
105 | 0x61, 0x3f, | ||
106 | 0x62, 0x2a, | ||
107 | 0x63, 0x25, | ||
108 | 0x64, 0x24, | ||
109 | 0x65, 0x1b, | ||
110 | 0x66, 0x5c, | ||
111 | |||
112 | 0x17, 0x22, | ||
113 | 0x18, 0x33, | ||
114 | 0x19, 0x03, | ||
115 | 0x1a, 0x01, | ||
116 | 0x22, 0xa4, | ||
117 | 0x23, 0x00, | ||
118 | 0x26, 0xa0, | ||
119 | |||
120 | 0x1d, 0xa0, | ||
121 | SLEEPMSEC, 300, | ||
122 | |||
123 | 0x14, 0x03, | ||
124 | |||
125 | ENDDEF, 0x0000 | ||
126 | }; | ||
127 | |||
128 | /* gamma value: 2.2 */ | ||
129 | static const unsigned int ams369fg06_22_250[] = { | ||
130 | 0x00, 0x3f, 0x2a, 0x27, 0x27, 0x1f, 0x44, | ||
131 | 0x00, 0x00, 0x17, 0x24, 0x26, 0x1f, 0x43, | ||
132 | 0x00, 0x3f, 0x2a, 0x25, 0x24, 0x1b, 0x5c, | ||
133 | }; | ||
134 | |||
135 | static const unsigned int ams369fg06_22_200[] = { | ||
136 | 0x00, 0x3f, 0x28, 0x29, 0x27, 0x21, 0x3e, | ||
137 | 0x00, 0x00, 0x10, 0x25, 0x27, 0x20, 0x3d, | ||
138 | 0x00, 0x3f, 0x28, 0x27, 0x25, 0x1d, 0x53, | ||
139 | }; | ||
140 | |||
141 | static const unsigned int ams369fg06_22_150[] = { | ||
142 | 0x00, 0x3f, 0x2d, 0x29, 0x28, 0x23, 0x37, | ||
143 | 0x00, 0x00, 0x0b, 0x25, 0x28, 0x22, 0x36, | ||
144 | 0x00, 0x3f, 0x2b, 0x28, 0x26, 0x1f, 0x4a, | ||
145 | }; | ||
146 | |||
147 | static const unsigned int ams369fg06_22_100[] = { | ||
148 | 0x00, 0x3f, 0x30, 0x2a, 0x2b, 0x24, 0x2f, | ||
149 | 0x00, 0x00, 0x00, 0x25, 0x29, 0x24, 0x2e, | ||
150 | 0x00, 0x3f, 0x2f, 0x29, 0x29, 0x21, 0x3f, | ||
151 | }; | ||
152 | |||
153 | static const unsigned int ams369fg06_22_50[] = { | ||
154 | 0x00, 0x3f, 0x3c, 0x2c, 0x2d, 0x27, 0x24, | ||
155 | 0x00, 0x00, 0x00, 0x22, 0x2a, 0x27, 0x23, | ||
156 | 0x00, 0x3f, 0x3b, 0x2c, 0x2b, 0x24, 0x31, | ||
157 | }; | ||
158 | |||
159 | struct ams369fg06_gamma { | ||
160 | unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; | ||
161 | }; | ||
162 | |||
163 | static struct ams369fg06_gamma gamma_table = { | ||
164 | .gamma_22_table[0] = (unsigned int *)&ams369fg06_22_50, | ||
165 | .gamma_22_table[1] = (unsigned int *)&ams369fg06_22_100, | ||
166 | .gamma_22_table[2] = (unsigned int *)&ams369fg06_22_150, | ||
167 | .gamma_22_table[3] = (unsigned int *)&ams369fg06_22_200, | ||
168 | .gamma_22_table[4] = (unsigned int *)&ams369fg06_22_250, | ||
169 | }; | ||
170 | |||
171 | static int ams369fg06_spi_write_byte(struct ams369fg06 *lcd, int addr, int data) | ||
172 | { | ||
173 | u16 buf[1]; | ||
174 | struct spi_message msg; | ||
175 | |||
176 | struct spi_transfer xfer = { | ||
177 | .len = 2, | ||
178 | .tx_buf = buf, | ||
179 | }; | ||
180 | |||
181 | buf[0] = (addr << 8) | data; | ||
182 | |||
183 | spi_message_init(&msg); | ||
184 | spi_message_add_tail(&xfer, &msg); | ||
185 | |||
186 | return spi_sync(lcd->spi, &msg); | ||
187 | } | ||
188 | |||
189 | static int ams369fg06_spi_write(struct ams369fg06 *lcd, unsigned char address, | ||
190 | unsigned char command) | ||
191 | { | ||
192 | int ret = 0; | ||
193 | |||
194 | if (address != DATA_ONLY) | ||
195 | ret = ams369fg06_spi_write_byte(lcd, 0x70, address); | ||
196 | if (command != COMMAND_ONLY) | ||
197 | ret = ams369fg06_spi_write_byte(lcd, 0x72, command); | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd, | ||
203 | const unsigned short *wbuf) | ||
204 | { | ||
205 | int ret = 0, i = 0; | ||
206 | |||
207 | while ((wbuf[i] & DEFMASK) != ENDDEF) { | ||
208 | if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { | ||
209 | ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]); | ||
210 | if (ret) | ||
211 | break; | ||
212 | } else | ||
213 | mdelay(wbuf[i+1]); | ||
214 | i += 2; | ||
215 | } | ||
216 | |||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int _ams369fg06_gamma_ctl(struct ams369fg06 *lcd, | ||
221 | const unsigned int *gamma) | ||
222 | { | ||
223 | unsigned int i = 0; | ||
224 | int ret = 0; | ||
225 | |||
226 | for (i = 0 ; i < GAMMA_TABLE_COUNT / 3; i++) { | ||
227 | ret = ams369fg06_spi_write(lcd, 0x40 + i, gamma[i]); | ||
228 | ret = ams369fg06_spi_write(lcd, 0x50 + i, gamma[i+7*1]); | ||
229 | ret = ams369fg06_spi_write(lcd, 0x60 + i, gamma[i+7*2]); | ||
230 | if (ret) { | ||
231 | dev_err(lcd->dev, "failed to set gamma table.\n"); | ||
232 | goto gamma_err; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | gamma_err: | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static int ams369fg06_gamma_ctl(struct ams369fg06 *lcd, int brightness) | ||
241 | { | ||
242 | int ret = 0; | ||
243 | int gamma = 0; | ||
244 | |||
245 | if ((brightness >= 0) && (brightness <= 50)) | ||
246 | gamma = 0; | ||
247 | else if ((brightness > 50) && (brightness <= 100)) | ||
248 | gamma = 1; | ||
249 | else if ((brightness > 100) && (brightness <= 150)) | ||
250 | gamma = 2; | ||
251 | else if ((brightness > 150) && (brightness <= 200)) | ||
252 | gamma = 3; | ||
253 | else if ((brightness > 200) && (brightness <= 255)) | ||
254 | gamma = 4; | ||
255 | |||
256 | ret = _ams369fg06_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | static int ams369fg06_ldi_init(struct ams369fg06 *lcd) | ||
262 | { | ||
263 | int ret, i; | ||
264 | static const unsigned short *init_seq[] = { | ||
265 | seq_setting, | ||
266 | seq_stand_by_off, | ||
267 | }; | ||
268 | |||
269 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { | ||
270 | ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]); | ||
271 | if (ret) | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static int ams369fg06_ldi_enable(struct ams369fg06 *lcd) | ||
279 | { | ||
280 | int ret, i; | ||
281 | static const unsigned short *init_seq[] = { | ||
282 | seq_stand_by_off, | ||
283 | seq_display_on, | ||
284 | }; | ||
285 | |||
286 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { | ||
287 | ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]); | ||
288 | if (ret) | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int ams369fg06_ldi_disable(struct ams369fg06 *lcd) | ||
296 | { | ||
297 | int ret, i; | ||
298 | |||
299 | static const unsigned short *init_seq[] = { | ||
300 | seq_display_off, | ||
301 | seq_stand_by_on, | ||
302 | }; | ||
303 | |||
304 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { | ||
305 | ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]); | ||
306 | if (ret) | ||
307 | break; | ||
308 | } | ||
309 | |||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static int ams369fg06_power_is_on(int power) | ||
314 | { | ||
315 | return ((power) <= FB_BLANK_NORMAL); | ||
316 | } | ||
317 | |||
318 | static int ams369fg06_power_on(struct ams369fg06 *lcd) | ||
319 | { | ||
320 | int ret = 0; | ||
321 | struct lcd_platform_data *pd = NULL; | ||
322 | struct backlight_device *bd = NULL; | ||
323 | |||
324 | pd = lcd->lcd_pd; | ||
325 | if (!pd) { | ||
326 | dev_err(lcd->dev, "platform data is NULL.\n"); | ||
327 | return -EFAULT; | ||
328 | } | ||
329 | |||
330 | bd = lcd->bd; | ||
331 | if (!bd) { | ||
332 | dev_err(lcd->dev, "backlight device is NULL.\n"); | ||
333 | return -EFAULT; | ||
334 | } | ||
335 | |||
336 | if (!pd->power_on) { | ||
337 | dev_err(lcd->dev, "power_on is NULL.\n"); | ||
338 | return -EFAULT; | ||
339 | } else { | ||
340 | pd->power_on(lcd->ld, 1); | ||
341 | mdelay(pd->power_on_delay); | ||
342 | } | ||
343 | |||
344 | if (!pd->reset) { | ||
345 | dev_err(lcd->dev, "reset is NULL.\n"); | ||
346 | return -EFAULT; | ||
347 | } else { | ||
348 | pd->reset(lcd->ld); | ||
349 | mdelay(pd->reset_delay); | ||
350 | } | ||
351 | |||
352 | ret = ams369fg06_ldi_init(lcd); | ||
353 | if (ret) { | ||
354 | dev_err(lcd->dev, "failed to initialize ldi.\n"); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | ret = ams369fg06_ldi_enable(lcd); | ||
359 | if (ret) { | ||
360 | dev_err(lcd->dev, "failed to enable ldi.\n"); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | /* set brightness to current value after power on or resume. */ | ||
365 | ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness); | ||
366 | if (ret) { | ||
367 | dev_err(lcd->dev, "lcd gamma setting failed.\n"); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int ams369fg06_power_off(struct ams369fg06 *lcd) | ||
375 | { | ||
376 | int ret = 0; | ||
377 | struct lcd_platform_data *pd = NULL; | ||
378 | |||
379 | pd = lcd->lcd_pd; | ||
380 | if (!pd) { | ||
381 | dev_err(lcd->dev, "platform data is NULL\n"); | ||
382 | return -EFAULT; | ||
383 | } | ||
384 | |||
385 | ret = ams369fg06_ldi_disable(lcd); | ||
386 | if (ret) { | ||
387 | dev_err(lcd->dev, "lcd setting failed.\n"); | ||
388 | return -EIO; | ||
389 | } | ||
390 | |||
391 | mdelay(pd->power_off_delay); | ||
392 | |||
393 | if (!pd->power_on) { | ||
394 | dev_err(lcd->dev, "power_on is NULL.\n"); | ||
395 | return -EFAULT; | ||
396 | } else | ||
397 | pd->power_on(lcd->ld, 0); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int ams369fg06_power(struct ams369fg06 *lcd, int power) | ||
403 | { | ||
404 | int ret = 0; | ||
405 | |||
406 | if (ams369fg06_power_is_on(power) && | ||
407 | !ams369fg06_power_is_on(lcd->power)) | ||
408 | ret = ams369fg06_power_on(lcd); | ||
409 | else if (!ams369fg06_power_is_on(power) && | ||
410 | ams369fg06_power_is_on(lcd->power)) | ||
411 | ret = ams369fg06_power_off(lcd); | ||
412 | |||
413 | if (!ret) | ||
414 | lcd->power = power; | ||
415 | |||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | static int ams369fg06_get_power(struct lcd_device *ld) | ||
420 | { | ||
421 | struct ams369fg06 *lcd = lcd_get_data(ld); | ||
422 | |||
423 | return lcd->power; | ||
424 | } | ||
425 | |||
426 | static int ams369fg06_set_power(struct lcd_device *ld, int power) | ||
427 | { | ||
428 | struct ams369fg06 *lcd = lcd_get_data(ld); | ||
429 | |||
430 | if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && | ||
431 | power != FB_BLANK_NORMAL) { | ||
432 | dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | return ams369fg06_power(lcd, power); | ||
437 | } | ||
438 | |||
439 | static int ams369fg06_get_brightness(struct backlight_device *bd) | ||
440 | { | ||
441 | return bd->props.brightness; | ||
442 | } | ||
443 | |||
444 | static int ams369fg06_set_brightness(struct backlight_device *bd) | ||
445 | { | ||
446 | int ret = 0; | ||
447 | int brightness = bd->props.brightness; | ||
448 | struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev); | ||
449 | |||
450 | if (brightness < MIN_BRIGHTNESS || | ||
451 | brightness > bd->props.max_brightness) { | ||
452 | dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", | ||
453 | MIN_BRIGHTNESS, MAX_BRIGHTNESS); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness); | ||
458 | if (ret) { | ||
459 | dev_err(&bd->dev, "lcd brightness setting failed.\n"); | ||
460 | return -EIO; | ||
461 | } | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static struct lcd_ops ams369fg06_lcd_ops = { | ||
467 | .get_power = ams369fg06_get_power, | ||
468 | .set_power = ams369fg06_set_power, | ||
469 | }; | ||
470 | |||
471 | static const struct backlight_ops ams369fg06_backlight_ops = { | ||
472 | .get_brightness = ams369fg06_get_brightness, | ||
473 | .update_status = ams369fg06_set_brightness, | ||
474 | }; | ||
475 | |||
476 | static int __devinit ams369fg06_probe(struct spi_device *spi) | ||
477 | { | ||
478 | int ret = 0; | ||
479 | struct ams369fg06 *lcd = NULL; | ||
480 | struct lcd_device *ld = NULL; | ||
481 | struct backlight_device *bd = NULL; | ||
482 | struct backlight_properties props; | ||
483 | |||
484 | lcd = kzalloc(sizeof(struct ams369fg06), GFP_KERNEL); | ||
485 | if (!lcd) | ||
486 | return -ENOMEM; | ||
487 | |||
488 | /* ams369fg06 lcd panel uses 3-wire 16bits SPI Mode. */ | ||
489 | spi->bits_per_word = 16; | ||
490 | |||
491 | ret = spi_setup(spi); | ||
492 | if (ret < 0) { | ||
493 | dev_err(&spi->dev, "spi setup failed.\n"); | ||
494 | goto out_free_lcd; | ||
495 | } | ||
496 | |||
497 | lcd->spi = spi; | ||
498 | lcd->dev = &spi->dev; | ||
499 | |||
500 | lcd->lcd_pd = spi->dev.platform_data; | ||
501 | if (!lcd->lcd_pd) { | ||
502 | dev_err(&spi->dev, "platform data is NULL\n"); | ||
503 | goto out_free_lcd; | ||
504 | } | ||
505 | |||
506 | ld = lcd_device_register("ams369fg06", &spi->dev, lcd, | ||
507 | &ams369fg06_lcd_ops); | ||
508 | if (IS_ERR(ld)) { | ||
509 | ret = PTR_ERR(ld); | ||
510 | goto out_free_lcd; | ||
511 | } | ||
512 | |||
513 | lcd->ld = ld; | ||
514 | |||
515 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
516 | props.type = BACKLIGHT_RAW; | ||
517 | props.max_brightness = MAX_BRIGHTNESS; | ||
518 | |||
519 | bd = backlight_device_register("ams369fg06-bl", &spi->dev, lcd, | ||
520 | &ams369fg06_backlight_ops, &props); | ||
521 | if (IS_ERR(bd)) { | ||
522 | ret = PTR_ERR(bd); | ||
523 | goto out_lcd_unregister; | ||
524 | } | ||
525 | |||
526 | bd->props.brightness = DEFAULT_BRIGHTNESS; | ||
527 | lcd->bd = bd; | ||
528 | |||
529 | if (!lcd->lcd_pd->lcd_enabled) { | ||
530 | /* | ||
531 | * if lcd panel was off from bootloader then | ||
532 | * current lcd status is powerdown and then | ||
533 | * it enables lcd panel. | ||
534 | */ | ||
535 | lcd->power = FB_BLANK_POWERDOWN; | ||
536 | |||
537 | ams369fg06_power(lcd, FB_BLANK_UNBLANK); | ||
538 | } else | ||
539 | lcd->power = FB_BLANK_UNBLANK; | ||
540 | |||
541 | dev_set_drvdata(&spi->dev, lcd); | ||
542 | |||
543 | dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n"); | ||
544 | |||
545 | return 0; | ||
546 | |||
547 | out_lcd_unregister: | ||
548 | lcd_device_unregister(ld); | ||
549 | out_free_lcd: | ||
550 | kfree(lcd); | ||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | static int __devexit ams369fg06_remove(struct spi_device *spi) | ||
555 | { | ||
556 | struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | ||
557 | |||
558 | ams369fg06_power(lcd, FB_BLANK_POWERDOWN); | ||
559 | backlight_device_unregister(lcd->bd); | ||
560 | lcd_device_unregister(lcd->ld); | ||
561 | kfree(lcd); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | #if defined(CONFIG_PM) | ||
567 | static unsigned int before_power; | ||
568 | |||
569 | static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg) | ||
570 | { | ||
571 | int ret = 0; | ||
572 | struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | ||
573 | |||
574 | dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); | ||
575 | |||
576 | before_power = lcd->power; | ||
577 | |||
578 | /* | ||
579 | * when lcd panel is suspend, lcd panel becomes off | ||
580 | * regardless of status. | ||
581 | */ | ||
582 | ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN); | ||
583 | |||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | static int ams369fg06_resume(struct spi_device *spi) | ||
588 | { | ||
589 | int ret = 0; | ||
590 | struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | ||
591 | |||
592 | /* | ||
593 | * after suspended, if lcd panel status is FB_BLANK_UNBLANK | ||
594 | * (at that time, before_power is FB_BLANK_UNBLANK) then | ||
595 | * it changes that status to FB_BLANK_POWERDOWN to get lcd on. | ||
596 | */ | ||
597 | if (before_power == FB_BLANK_UNBLANK) | ||
598 | lcd->power = FB_BLANK_POWERDOWN; | ||
599 | |||
600 | dev_dbg(&spi->dev, "before_power = %d\n", before_power); | ||
601 | |||
602 | ret = ams369fg06_power(lcd, before_power); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | #else | ||
607 | #define ams369fg06_suspend NULL | ||
608 | #define ams369fg06_resume NULL | ||
609 | #endif | ||
610 | |||
611 | static void ams369fg06_shutdown(struct spi_device *spi) | ||
612 | { | ||
613 | struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); | ||
614 | |||
615 | ams369fg06_power(lcd, FB_BLANK_POWERDOWN); | ||
616 | } | ||
617 | |||
618 | static struct spi_driver ams369fg06_driver = { | ||
619 | .driver = { | ||
620 | .name = "ams369fg06", | ||
621 | .bus = &spi_bus_type, | ||
622 | .owner = THIS_MODULE, | ||
623 | }, | ||
624 | .probe = ams369fg06_probe, | ||
625 | .remove = __devexit_p(ams369fg06_remove), | ||
626 | .shutdown = ams369fg06_shutdown, | ||
627 | .suspend = ams369fg06_suspend, | ||
628 | .resume = ams369fg06_resume, | ||
629 | }; | ||
630 | |||
631 | static int __init ams369fg06_init(void) | ||
632 | { | ||
633 | return spi_register_driver(&ams369fg06_driver); | ||
634 | } | ||
635 | |||
636 | static void __exit ams369fg06_exit(void) | ||
637 | { | ||
638 | spi_unregister_driver(&ams369fg06_driver); | ||
639 | } | ||
640 | |||
641 | module_init(ams369fg06_init); | ||
642 | module_exit(ams369fg06_exit); | ||
643 | |||
644 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | ||
645 | MODULE_DESCRIPTION("ams369fg06 LCD Driver"); | ||
646 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 7281b2506a67..5934655eb1ff 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c | |||
@@ -668,6 +668,7 @@ static int ld9040_probe(struct spi_device *spi) | |||
668 | struct ld9040 *lcd = NULL; | 668 | struct ld9040 *lcd = NULL; |
669 | struct lcd_device *ld = NULL; | 669 | struct lcd_device *ld = NULL; |
670 | struct backlight_device *bd = NULL; | 670 | struct backlight_device *bd = NULL; |
671 | struct backlight_properties props; | ||
671 | 672 | ||
672 | lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL); | 673 | lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL); |
673 | if (!lcd) | 674 | if (!lcd) |
@@ -699,14 +700,17 @@ static int ld9040_probe(struct spi_device *spi) | |||
699 | 700 | ||
700 | lcd->ld = ld; | 701 | lcd->ld = ld; |
701 | 702 | ||
703 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
704 | props.type = BACKLIGHT_RAW; | ||
705 | props.max_brightness = MAX_BRIGHTNESS; | ||
706 | |||
702 | bd = backlight_device_register("ld9040-bl", &spi->dev, | 707 | bd = backlight_device_register("ld9040-bl", &spi->dev, |
703 | lcd, &ld9040_backlight_ops, NULL); | 708 | lcd, &ld9040_backlight_ops, &props); |
704 | if (IS_ERR(ld)) { | 709 | if (IS_ERR(bd)) { |
705 | ret = PTR_ERR(ld); | 710 | ret = PTR_ERR(bd); |
706 | goto out_free_lcd; | 711 | goto out_unregister_lcd; |
707 | } | 712 | } |
708 | 713 | ||
709 | bd->props.max_brightness = MAX_BRIGHTNESS; | ||
710 | bd->props.brightness = MAX_BRIGHTNESS; | 714 | bd->props.brightness = MAX_BRIGHTNESS; |
711 | lcd->bd = bd; | 715 | lcd->bd = bd; |
712 | 716 | ||
@@ -731,6 +735,8 @@ static int ld9040_probe(struct spi_device *spi) | |||
731 | dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); | 735 | dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); |
732 | return 0; | 736 | return 0; |
733 | 737 | ||
738 | out_unregister_lcd: | ||
739 | lcd_device_unregister(lcd->ld); | ||
734 | out_free_lcd: | 740 | out_free_lcd: |
735 | kfree(lcd); | 741 | kfree(lcd); |
736 | return ret; | 742 | return ret; |
@@ -741,6 +747,7 @@ static int __devexit ld9040_remove(struct spi_device *spi) | |||
741 | struct ld9040 *lcd = dev_get_drvdata(&spi->dev); | 747 | struct ld9040 *lcd = dev_get_drvdata(&spi->dev); |
742 | 748 | ||
743 | ld9040_power(lcd, FB_BLANK_POWERDOWN); | 749 | ld9040_power(lcd, FB_BLANK_POWERDOWN); |
750 | backlight_device_unregister(lcd->bd); | ||
744 | lcd_device_unregister(lcd->ld); | 751 | lcd_device_unregister(lcd->ld); |
745 | kfree(lcd); | 752 | kfree(lcd); |
746 | 753 | ||
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 322040f686c2..694e5aab0d69 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c | |||
@@ -738,6 +738,7 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) | |||
738 | struct s6e63m0 *lcd = NULL; | 738 | struct s6e63m0 *lcd = NULL; |
739 | struct lcd_device *ld = NULL; | 739 | struct lcd_device *ld = NULL; |
740 | struct backlight_device *bd = NULL; | 740 | struct backlight_device *bd = NULL; |
741 | struct backlight_properties props; | ||
741 | 742 | ||
742 | lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL); | 743 | lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL); |
743 | if (!lcd) | 744 | if (!lcd) |
@@ -769,16 +770,18 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) | |||
769 | 770 | ||
770 | lcd->ld = ld; | 771 | lcd->ld = ld; |
771 | 772 | ||
773 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
774 | props.type = BACKLIGHT_RAW; | ||
775 | props.max_brightness = MAX_BRIGHTNESS; | ||
776 | |||
772 | bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, | 777 | bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, |
773 | &s6e63m0_backlight_ops, NULL); | 778 | &s6e63m0_backlight_ops, &props); |
774 | if (IS_ERR(bd)) { | 779 | if (IS_ERR(bd)) { |
775 | ret = PTR_ERR(bd); | 780 | ret = PTR_ERR(bd); |
776 | goto out_lcd_unregister; | 781 | goto out_lcd_unregister; |
777 | } | 782 | } |
778 | 783 | ||
779 | bd->props.max_brightness = MAX_BRIGHTNESS; | ||
780 | bd->props.brightness = MAX_BRIGHTNESS; | 784 | bd->props.brightness = MAX_BRIGHTNESS; |
781 | bd->props.type = BACKLIGHT_RAW; | ||
782 | lcd->bd = bd; | 785 | lcd->bd = bd; |
783 | 786 | ||
784 | /* | 787 | /* |
@@ -840,7 +843,7 @@ static int __devexit s6e63m0_remove(struct spi_device *spi) | |||
840 | } | 843 | } |
841 | 844 | ||
842 | #if defined(CONFIG_PM) | 845 | #if defined(CONFIG_PM) |
843 | unsigned int before_power; | 846 | static unsigned int before_power; |
844 | 847 | ||
845 | static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) | 848 | static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) |
846 | { | 849 | { |
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 03bc471c3eed..f815283667af 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -26,6 +26,36 @@ config XEN_SELFBALLOONING | |||
26 | kernel boot parameter. Note that systems without a sufficiently | 26 | kernel boot parameter. Note that systems without a sufficiently |
27 | large swap device should not enable self-ballooning. | 27 | large swap device should not enable self-ballooning. |
28 | 28 | ||
29 | config XEN_BALLOON_MEMORY_HOTPLUG | ||
30 | bool "Memory hotplug support for Xen balloon driver" | ||
31 | default n | ||
32 | depends on XEN_BALLOON && MEMORY_HOTPLUG | ||
33 | help | ||
34 | Memory hotplug support for Xen balloon driver allows expanding memory | ||
35 | available for the system above limit declared at system startup. | ||
36 | It is very useful on critical systems which require long | ||
37 | run without rebooting. | ||
38 | |||
39 | Memory could be hotplugged in following steps: | ||
40 | |||
41 | 1) dom0: xl mem-max <domU> <maxmem> | ||
42 | where <maxmem> is >= requested memory size, | ||
43 | |||
44 | 2) dom0: xl mem-set <domU> <memory> | ||
45 | where <memory> is requested memory size; alternatively memory | ||
46 | could be added by writing proper value to | ||
47 | /sys/devices/system/xen_memory/xen_memory0/target or | ||
48 | /sys/devices/system/xen_memory/xen_memory0/target_kb on dumU, | ||
49 | |||
50 | 3) domU: for i in /sys/devices/system/memory/memory*/state; do \ | ||
51 | [ "`cat "$i"`" = offline ] && echo online > "$i"; done | ||
52 | |||
53 | Memory could be onlined automatically on domU by adding following line to udev rules: | ||
54 | |||
55 | SUBSYSTEM=="memory", ACTION=="add", RUN+="/bin/sh -c '[ -f /sys$devpath/state ] && echo online > /sys$devpath/state'" | ||
56 | |||
57 | In that case step 3 should be omitted. | ||
58 | |||
29 | config XEN_SCRUB_PAGES | 59 | config XEN_SCRUB_PAGES |
30 | bool "Scrub pages before returning them to system" | 60 | bool "Scrub pages before returning them to system" |
31 | depends on XEN_BALLOON | 61 | depends on XEN_BALLOON |
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index f54290baa3db..5dfd8f8ff07f 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -4,6 +4,12 @@ | |||
4 | * Copyright (c) 2003, B Dragovic | 4 | * Copyright (c) 2003, B Dragovic |
5 | * Copyright (c) 2003-2004, M Williamson, K Fraser | 5 | * Copyright (c) 2003-2004, M Williamson, K Fraser |
6 | * Copyright (c) 2005 Dan M. Smith, IBM Corporation | 6 | * Copyright (c) 2005 Dan M. Smith, IBM Corporation |
7 | * Copyright (c) 2010 Daniel Kiper | ||
8 | * | ||
9 | * Memory hotplug support was written by Daniel Kiper. Work on | ||
10 | * it was sponsored by Google under Google Summer of Code 2010 | ||
11 | * program. Jeremy Fitzhardinge from Citrix was the mentor for | ||
12 | * this project. | ||
7 | * | 13 | * |
8 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License version 2 | 15 | * modify it under the terms of the GNU General Public License version 2 |
@@ -40,6 +46,9 @@ | |||
40 | #include <linux/mutex.h> | 46 | #include <linux/mutex.h> |
41 | #include <linux/list.h> | 47 | #include <linux/list.h> |
42 | #include <linux/gfp.h> | 48 | #include <linux/gfp.h> |
49 | #include <linux/notifier.h> | ||
50 | #include <linux/memory.h> | ||
51 | #include <linux/memory_hotplug.h> | ||
43 | 52 | ||
44 | #include <asm/page.h> | 53 | #include <asm/page.h> |
45 | #include <asm/pgalloc.h> | 54 | #include <asm/pgalloc.h> |
@@ -194,6 +203,87 @@ static enum bp_state update_schedule(enum bp_state state) | |||
194 | return BP_EAGAIN; | 203 | return BP_EAGAIN; |
195 | } | 204 | } |
196 | 205 | ||
206 | #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG | ||
207 | static long current_credit(void) | ||
208 | { | ||
209 | return balloon_stats.target_pages - balloon_stats.current_pages - | ||
210 | balloon_stats.hotplug_pages; | ||
211 | } | ||
212 | |||
213 | static bool balloon_is_inflated(void) | ||
214 | { | ||
215 | if (balloon_stats.balloon_low || balloon_stats.balloon_high || | ||
216 | balloon_stats.balloon_hotplug) | ||
217 | return true; | ||
218 | else | ||
219 | return false; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * reserve_additional_memory() adds memory region of size >= credit above | ||
224 | * max_pfn. New region is section aligned and size is modified to be multiple | ||
225 | * of section size. Those features allow optimal use of address space and | ||
226 | * establish proper alignment when this function is called first time after | ||
227 | * boot (last section not fully populated at boot time contains unused memory | ||
228 | * pages with PG_reserved bit not set; online_pages_range() does not allow page | ||
229 | * onlining in whole range if first onlined page does not have PG_reserved | ||
230 | * bit set). Real size of added memory is established at page onlining stage. | ||
231 | */ | ||
232 | |||
233 | static enum bp_state reserve_additional_memory(long credit) | ||
234 | { | ||
235 | int nid, rc; | ||
236 | u64 hotplug_start_paddr; | ||
237 | unsigned long balloon_hotplug = credit; | ||
238 | |||
239 | hotplug_start_paddr = PFN_PHYS(SECTION_ALIGN_UP(max_pfn)); | ||
240 | balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION); | ||
241 | nid = memory_add_physaddr_to_nid(hotplug_start_paddr); | ||
242 | |||
243 | rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT); | ||
244 | |||
245 | if (rc) { | ||
246 | pr_info("xen_balloon: %s: add_memory() failed: %i\n", __func__, rc); | ||
247 | return BP_EAGAIN; | ||
248 | } | ||
249 | |||
250 | balloon_hotplug -= credit; | ||
251 | |||
252 | balloon_stats.hotplug_pages += credit; | ||
253 | balloon_stats.balloon_hotplug = balloon_hotplug; | ||
254 | |||
255 | return BP_DONE; | ||
256 | } | ||
257 | |||
258 | static void xen_online_page(struct page *page) | ||
259 | { | ||
260 | __online_page_set_limits(page); | ||
261 | |||
262 | mutex_lock(&balloon_mutex); | ||
263 | |||
264 | __balloon_append(page); | ||
265 | |||
266 | if (balloon_stats.hotplug_pages) | ||
267 | --balloon_stats.hotplug_pages; | ||
268 | else | ||
269 | --balloon_stats.balloon_hotplug; | ||
270 | |||
271 | mutex_unlock(&balloon_mutex); | ||
272 | } | ||
273 | |||
274 | static int xen_memory_notifier(struct notifier_block *nb, unsigned long val, void *v) | ||
275 | { | ||
276 | if (val == MEM_ONLINE) | ||
277 | schedule_delayed_work(&balloon_worker, 0); | ||
278 | |||
279 | return NOTIFY_OK; | ||
280 | } | ||
281 | |||
282 | static struct notifier_block xen_memory_nb = { | ||
283 | .notifier_call = xen_memory_notifier, | ||
284 | .priority = 0 | ||
285 | }; | ||
286 | #else | ||
197 | static long current_credit(void) | 287 | static long current_credit(void) |
198 | { | 288 | { |
199 | unsigned long target = balloon_stats.target_pages; | 289 | unsigned long target = balloon_stats.target_pages; |
@@ -206,6 +296,21 @@ static long current_credit(void) | |||
206 | return target - balloon_stats.current_pages; | 296 | return target - balloon_stats.current_pages; |
207 | } | 297 | } |
208 | 298 | ||
299 | static bool balloon_is_inflated(void) | ||
300 | { | ||
301 | if (balloon_stats.balloon_low || balloon_stats.balloon_high) | ||
302 | return true; | ||
303 | else | ||
304 | return false; | ||
305 | } | ||
306 | |||
307 | static enum bp_state reserve_additional_memory(long credit) | ||
308 | { | ||
309 | balloon_stats.target_pages = balloon_stats.current_pages; | ||
310 | return BP_DONE; | ||
311 | } | ||
312 | #endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */ | ||
313 | |||
209 | static enum bp_state increase_reservation(unsigned long nr_pages) | 314 | static enum bp_state increase_reservation(unsigned long nr_pages) |
210 | { | 315 | { |
211 | int rc; | 316 | int rc; |
@@ -217,6 +322,15 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
217 | .domid = DOMID_SELF | 322 | .domid = DOMID_SELF |
218 | }; | 323 | }; |
219 | 324 | ||
325 | #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG | ||
326 | if (!balloon_stats.balloon_low && !balloon_stats.balloon_high) { | ||
327 | nr_pages = min(nr_pages, balloon_stats.balloon_hotplug); | ||
328 | balloon_stats.hotplug_pages += nr_pages; | ||
329 | balloon_stats.balloon_hotplug -= nr_pages; | ||
330 | return BP_DONE; | ||
331 | } | ||
332 | #endif | ||
333 | |||
220 | if (nr_pages > ARRAY_SIZE(frame_list)) | 334 | if (nr_pages > ARRAY_SIZE(frame_list)) |
221 | nr_pages = ARRAY_SIZE(frame_list); | 335 | nr_pages = ARRAY_SIZE(frame_list); |
222 | 336 | ||
@@ -279,6 +393,15 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
279 | .domid = DOMID_SELF | 393 | .domid = DOMID_SELF |
280 | }; | 394 | }; |
281 | 395 | ||
396 | #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG | ||
397 | if (balloon_stats.hotplug_pages) { | ||
398 | nr_pages = min(nr_pages, balloon_stats.hotplug_pages); | ||
399 | balloon_stats.hotplug_pages -= nr_pages; | ||
400 | balloon_stats.balloon_hotplug += nr_pages; | ||
401 | return BP_DONE; | ||
402 | } | ||
403 | #endif | ||
404 | |||
282 | if (nr_pages > ARRAY_SIZE(frame_list)) | 405 | if (nr_pages > ARRAY_SIZE(frame_list)) |
283 | nr_pages = ARRAY_SIZE(frame_list); | 406 | nr_pages = ARRAY_SIZE(frame_list); |
284 | 407 | ||
@@ -340,8 +463,12 @@ static void balloon_process(struct work_struct *work) | |||
340 | do { | 463 | do { |
341 | credit = current_credit(); | 464 | credit = current_credit(); |
342 | 465 | ||
343 | if (credit > 0) | 466 | if (credit > 0) { |
344 | state = increase_reservation(credit); | 467 | if (balloon_is_inflated()) |
468 | state = increase_reservation(credit); | ||
469 | else | ||
470 | state = reserve_additional_memory(credit); | ||
471 | } | ||
345 | 472 | ||
346 | if (credit < 0) | 473 | if (credit < 0) |
347 | state = decrease_reservation(-credit, GFP_BALLOON); | 474 | state = decrease_reservation(-credit, GFP_BALLOON); |
@@ -448,6 +575,14 @@ static int __init balloon_init(void) | |||
448 | balloon_stats.retry_count = 1; | 575 | balloon_stats.retry_count = 1; |
449 | balloon_stats.max_retry_count = RETRY_UNLIMITED; | 576 | balloon_stats.max_retry_count = RETRY_UNLIMITED; |
450 | 577 | ||
578 | #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG | ||
579 | balloon_stats.hotplug_pages = 0; | ||
580 | balloon_stats.balloon_hotplug = 0; | ||
581 | |||
582 | set_online_page_callback(&xen_online_page); | ||
583 | register_memory_notifier(&xen_memory_nb); | ||
584 | #endif | ||
585 | |||
451 | /* | 586 | /* |
452 | * Initialise the balloon with excess memory space. We need | 587 | * Initialise the balloon with excess memory space. We need |
453 | * to make sure we don't add memory which doesn't exist or | 588 | * to make sure we don't add memory which doesn't exist or |