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

Configure Feed

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

at v2.6.33-rc8 175 lines 3.6 kB view raw
1/* 2 * Atmel SSC driver 3 * 4 * Copyright (C) 2007 Atmel Corporation 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/platform_device.h> 12#include <linux/list.h> 13#include <linux/clk.h> 14#include <linux/err.h> 15#include <linux/io.h> 16#include <linux/spinlock.h> 17#include <linux/atmel-ssc.h> 18 19/* Serialize access to ssc_list and user count */ 20static DEFINE_SPINLOCK(user_lock); 21static LIST_HEAD(ssc_list); 22 23struct ssc_device *ssc_request(unsigned int ssc_num) 24{ 25 int ssc_valid = 0; 26 struct ssc_device *ssc; 27 28 spin_lock(&user_lock); 29 list_for_each_entry(ssc, &ssc_list, list) { 30 if (ssc->pdev->id == ssc_num) { 31 ssc_valid = 1; 32 break; 33 } 34 } 35 36 if (!ssc_valid) { 37 spin_unlock(&user_lock); 38 pr_err("ssc: ssc%d platform device is missing\n", ssc_num); 39 return ERR_PTR(-ENODEV); 40 } 41 42 if (ssc->user) { 43 spin_unlock(&user_lock); 44 dev_dbg(&ssc->pdev->dev, "module busy\n"); 45 return ERR_PTR(-EBUSY); 46 } 47 ssc->user++; 48 spin_unlock(&user_lock); 49 50 clk_enable(ssc->clk); 51 52 return ssc; 53} 54EXPORT_SYMBOL(ssc_request); 55 56void ssc_free(struct ssc_device *ssc) 57{ 58 spin_lock(&user_lock); 59 if (ssc->user) { 60 ssc->user--; 61 clk_disable(ssc->clk); 62 } else { 63 dev_dbg(&ssc->pdev->dev, "device already free\n"); 64 } 65 spin_unlock(&user_lock); 66} 67EXPORT_SYMBOL(ssc_free); 68 69static int __init ssc_probe(struct platform_device *pdev) 70{ 71 int retval = 0; 72 struct resource *regs; 73 struct ssc_device *ssc; 74 75 ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL); 76 if (!ssc) { 77 dev_dbg(&pdev->dev, "out of memory\n"); 78 retval = -ENOMEM; 79 goto out; 80 } 81 82 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 83 if (!regs) { 84 dev_dbg(&pdev->dev, "no mmio resource defined\n"); 85 retval = -ENXIO; 86 goto out_free; 87 } 88 89 ssc->clk = clk_get(&pdev->dev, "pclk"); 90 if (IS_ERR(ssc->clk)) { 91 dev_dbg(&pdev->dev, "no pclk clock defined\n"); 92 retval = -ENXIO; 93 goto out_free; 94 } 95 96 ssc->pdev = pdev; 97 ssc->regs = ioremap(regs->start, regs->end - regs->start + 1); 98 if (!ssc->regs) { 99 dev_dbg(&pdev->dev, "ioremap failed\n"); 100 retval = -EINVAL; 101 goto out_clk; 102 } 103 104 /* disable all interrupts */ 105 clk_enable(ssc->clk); 106 ssc_writel(ssc->regs, IDR, ~0UL); 107 ssc_readl(ssc->regs, SR); 108 clk_disable(ssc->clk); 109 110 ssc->irq = platform_get_irq(pdev, 0); 111 if (!ssc->irq) { 112 dev_dbg(&pdev->dev, "could not get irq\n"); 113 retval = -ENXIO; 114 goto out_unmap; 115 } 116 117 spin_lock(&user_lock); 118 list_add_tail(&ssc->list, &ssc_list); 119 spin_unlock(&user_lock); 120 121 platform_set_drvdata(pdev, ssc); 122 123 dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n", 124 ssc->regs, ssc->irq); 125 126 goto out; 127 128out_unmap: 129 iounmap(ssc->regs); 130out_clk: 131 clk_put(ssc->clk); 132out_free: 133 kfree(ssc); 134out: 135 return retval; 136} 137 138static int __devexit ssc_remove(struct platform_device *pdev) 139{ 140 struct ssc_device *ssc = platform_get_drvdata(pdev); 141 142 spin_lock(&user_lock); 143 iounmap(ssc->regs); 144 clk_put(ssc->clk); 145 list_del(&ssc->list); 146 kfree(ssc); 147 spin_unlock(&user_lock); 148 149 return 0; 150} 151 152static struct platform_driver ssc_driver = { 153 .remove = __devexit_p(ssc_remove), 154 .driver = { 155 .name = "ssc", 156 .owner = THIS_MODULE, 157 }, 158}; 159 160static int __init ssc_init(void) 161{ 162 return platform_driver_probe(&ssc_driver, ssc_probe); 163} 164module_init(ssc_init); 165 166static void __exit ssc_exit(void) 167{ 168 platform_driver_unregister(&ssc_driver); 169} 170module_exit(ssc_exit); 171 172MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); 173MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); 174MODULE_LICENSE("GPL"); 175MODULE_ALIAS("platform:ssc");