1 /* 2 * Copyright (C) 2014 Free Electrons 3 * Copyright (C) 2014 Atmel 4 * 5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/clk.h> 21 #include <linux/mfd/atmel-hlcdc.h> 22 #include <linux/mfd/core.h> 23 #include <linux/module.h> 24 #include <linux/platform_device.h> 25 #include <linux/regmap.h> 26 27 #define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4) 28 29 static const struct mfd_cell atmel_hlcdc_cells[] = { 30 { 31 .name = "atmel-hlcdc-pwm", 32 .of_compatible = "atmel,hlcdc-pwm", 33 }, 34 { 35 .name = "atmel-hlcdc-dc", 36 .of_compatible = "atmel,hlcdc-display-controller", 37 }, 38 }; 39 40 static const struct regmap_config atmel_hlcdc_regmap_config = { 41 .reg_bits = 32, 42 .val_bits = 32, 43 .reg_stride = 4, 44 .max_register = ATMEL_HLCDC_REG_MAX, 45 }; 46 47 static int atmel_hlcdc_probe(struct platform_device *pdev) 48 { 49 struct device *dev = &pdev->dev; 50 struct atmel_hlcdc *hlcdc; 51 struct resource *res; 52 void __iomem *regs; 53 54 hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL); 55 if (!hlcdc) 56 return -ENOMEM; 57 58 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 59 regs = devm_ioremap_resource(dev, res); 60 if (IS_ERR(regs)) 61 return PTR_ERR(regs); 62 63 hlcdc->irq = platform_get_irq(pdev, 0); 64 if (hlcdc->irq < 0) 65 return hlcdc->irq; 66 67 hlcdc->periph_clk = devm_clk_get(dev, "periph_clk"); 68 if (IS_ERR(hlcdc->periph_clk)) { 69 dev_err(dev, "failed to get peripheral clock\n"); 70 return PTR_ERR(hlcdc->periph_clk); 71 } 72 73 hlcdc->sys_clk = devm_clk_get(dev, "sys_clk"); 74 if (IS_ERR(hlcdc->sys_clk)) { 75 dev_err(dev, "failed to get system clock\n"); 76 return PTR_ERR(hlcdc->sys_clk); 77 } 78 79 hlcdc->slow_clk = devm_clk_get(dev, "slow_clk"); 80 if (IS_ERR(hlcdc->slow_clk)) { 81 dev_err(dev, "failed to get slow clock\n"); 82 return PTR_ERR(hlcdc->slow_clk); 83 } 84 85 hlcdc->regmap = devm_regmap_init_mmio(dev, regs, 86 &atmel_hlcdc_regmap_config); 87 if (IS_ERR(hlcdc->regmap)) 88 return PTR_ERR(hlcdc->regmap); 89 90 dev_set_drvdata(dev, hlcdc); 91 92 return mfd_add_devices(dev, -1, atmel_hlcdc_cells, 93 ARRAY_SIZE(atmel_hlcdc_cells), 94 NULL, 0, NULL); 95 } 96 97 static int atmel_hlcdc_remove(struct platform_device *pdev) 98 { 99 mfd_remove_devices(&pdev->dev); 100 101 return 0; 102 } 103 104 static const struct of_device_id atmel_hlcdc_match[] = { 105 { .compatible = "atmel,sama5d3-hlcdc" }, 106 { /* sentinel */ }, 107 }; 108 109 static struct platform_driver atmel_hlcdc_driver = { 110 .probe = atmel_hlcdc_probe, 111 .remove = atmel_hlcdc_remove, 112 .driver = { 113 .name = "atmel-hlcdc", 114 .of_match_table = atmel_hlcdc_match, 115 }, 116 }; 117 module_platform_driver(atmel_hlcdc_driver); 118 119 MODULE_ALIAS("platform:atmel-hlcdc"); 120 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>"); 121 MODULE_DESCRIPTION("Atmel HLCDC driver"); 122 MODULE_LICENSE("GPL v2"); 123