@@ -0,0 +1,176 @@+/*+*CopyrightIntelCorporation(C)2017.AllRightsReserved+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsandconditionsoftheGNUGeneralPublicLicense,+*version2,aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopeitwillbeuseful,butWITHOUT+*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor+*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor+*moredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicensealongwith+*thisprogram.Ifnot,see<http://www.gnu.org/licenses/>.+*+*ResetdriverforAlteraArria10MAX5SystemResourceChip+*+*Adaptedfromreset-socfpga.c+*/++#include<linux/err.h>+#include<linux/io.h>+#include<linux/mfd/altera-a10sr.h>+#include<linux/module.h>+#include<linux/of.h>+#include<linux/platform_device.h>+#include<linux/reset-controller.h>+#include<linux/types.h>++#include<dt-bindings/reset/altr,rst-mgr-a10sr.h>++/* Number of A10 System Controller Resets */+#define A10SR_RESETS 16++structa10sr_reset{+structreset_controller_devrcdev;+structregmap*regmap;+};++staticinlinestructa10sr_reset*to_a10sr_rst(structreset_controller_dev*rc)+{+returncontainer_of(rc,structa10sr_reset,rcdev);+}++staticinlineinta10sr_reset_shift(unsignedlongid)+{+switch(id){+caseA10SR_RESET_ENET_HPS:+return1;+caseA10SR_RESET_PCIE:+caseA10SR_RESET_FILE:+caseA10SR_RESET_BQSPI:+caseA10SR_RESET_USB:+returnid+11;+default:+return-EINVAL;+}+}++staticinta10sr_reset_update(structreset_controller_dev*rcdev,+unsignedlongid,boolassert)+{+structa10sr_reset*a10r=to_a10sr_rst(rcdev);+intoffset=a10sr_reset_shift(id);+u8mask=ALTR_A10SR_REG_BIT_MASK(offset);+intindex=ALTR_A10SR_HPS_RST_REG+ALTR_A10SR_REG_OFFSET(offset);++if(id>=rcdev->nr_resets)+return-EINVAL;++returnregmap_update_bits(a10r->regmap,index,mask,assert?0:mask);+}++staticinta10sr_reset_assert(structreset_controller_dev*rcdev,+unsignedlongid)+{+returna10sr_reset_update(rcdev,id,true);+}++staticinta10sr_reset_deassert(structreset_controller_dev*rcdev,+unsignedlongid)+{+returna10sr_reset_update(rcdev,id,false);+}++staticinta10sr_reset_status(structreset_controller_dev*rcdev,+unsignedlongid)+{+interror;+structa10sr_reset*a10r=to_a10sr_rst(rcdev);+intoffset=a10sr_reset_shift(id);+u8mask=ALTR_A10SR_REG_BIT_MASK(offset);+intindex=ALTR_A10SR_HPS_RST_REG+ALTR_A10SR_REG_OFFSET(offset);+unsignedintvalue;++if(id>=rcdev->nr_resets)+return-EINVAL;++error=regmap_read(a10r->regmap,index,&value);+if(error<0)+return-ENOMEM;++return!!(value&mask);+}++staticconststructreset_control_opsa10sr_reset_ops={+.assert=a10sr_reset_assert,+.deassert=a10sr_reset_deassert,+.status=a10sr_reset_status,+};++staticconststructof_device_ida10sr_reset_of_match[];+staticinta10sr_reset_probe(structplatform_device*pdev)+{+structaltr_a10sr*a10sr=dev_get_drvdata(pdev->dev.parent);+structa10sr_reset*a10r;+structdevice*dev=&pdev->dev;+structdevice_node*np=dev->of_node;++/* Ensure we have a valid DT entry. */+np=of_find_matching_node(NULL,a10sr_reset_of_match);+if(!np){+dev_err(&pdev->dev,"A10 Reset DT Entry not found\n");+return-EINVAL;+}++if(!of_find_property(np,"#reset-cells",NULL)){+dev_err(&pdev->dev,"%s missing #reset-cells property\n",+np->full_name);+return-EINVAL;+}++a10r=devm_kzalloc(&pdev->dev,sizeof(structa10sr_reset),+GFP_KERNEL);+if(!a10r)+return-ENOMEM;++a10r->rcdev.owner=THIS_MODULE;+a10r->rcdev.nr_resets=A10SR_RESETS;+a10r->rcdev.ops=&a10sr_reset_ops;+a10r->rcdev.of_node=np;+a10r->regmap=a10sr->regmap;++platform_set_drvdata(pdev,a10r);++returndevm_reset_controller_register(dev,&a10r->rcdev);+}++staticinta10sr_reset_remove(structplatform_device*pdev)+{+structa10sr_reset*a10r=platform_get_drvdata(pdev);++reset_controller_unregister(&a10r->rcdev);++return0;+}++staticconststructof_device_ida10sr_reset_of_match[]={+{.compatible="altr,a10sr-reset"},+{},+};+MODULE_DEVICE_TABLE(of,a10sr_reset_of_match);++staticstructplatform_drivera10sr_reset_driver={+.probe=a10sr_reset_probe,+.remove=a10sr_reset_remove,+.driver={+.name="altr_a10sr_reset",+.owner=THIS_MODULE,+},+};+module_platform_driver(a10sr_reset_driver);++MODULE_AUTHOR("Thor Thayer <thor.thayer@linux.intel.com>");+MODULE_DESCRIPTION("Altera Arria10 System Resource Reset Controller Driver");+MODULE_LICENSE("GPL v2");
@@ -18,6 +18,7 @@ The A10SR consists of these sub-devices: Device Description ------ ---------- a10sr_gpio GPIO Controller+a10sr_rst Reset Controller Arria10 GPIO Required Properties:
@@ -27,6 +28,11 @@ Required Properties: the second cell is used to specify flags. See ../gpio/gpio.txt for more information.+Arria10 Peripheral PHY Reset+Required Properties:+- compatible : Should be "altr,a10sr-reset"+- #reset-cells : Should be one.+ Example: resource-manager at 0 {
Please follow the RESET_<SoC> convention and sort alphabetically.
quoted hunk
+ tristate "Altera Arria10 System Resource Reset"+ depends on MFD_ALTERA_A10SR+ help+ This option enables support for the external reset functions for+ peripheral PHYs on the Altera Arria10 System Resource Chip.+ config RESET_OXNAS bool
Please follow the RESET_<SoC> convention and sort alphabetically.
Whoops. Thanks.
quoted
+ tristate "Altera Arria10 System Resource Reset"+ depends on MFD_ALTERA_A10SR+ help+ This option enables support for the external reset functions for+ peripheral PHYs on the Altera Arria10 System Resource Chip.+ config RESET_OXNAS bool
+#include <linux/mfd/altera-a10sr.h>+#include <linux/module.h>+#include <linux/of.h>+#include <linux/platform_device.h>+#include <linux/reset-controller.h>+#include <linux/types.h>++#include <dt-bindings/reset/altr,rst-mgr-a10sr.h>++/* Number of A10 System Controller Resets */+#define A10SR_RESETS 16
So 16 resets...
quoted
+struct a10sr_reset {+ struct reset_controller_dev rcdev;+ struct regmap *regmap;+};++static inline struct a10sr_reset *to_a10sr_rst(struct reset_controller_dev *rc)+{+ return container_of(rc, struct a10sr_reset, rcdev);+}++static inline int a10sr_reset_shift(unsigned long id)+{+ switch (id) {+ case A10SR_RESET_ENET_HPS:+ return 1;+ case A10SR_RESET_PCIE:+ case A10SR_RESET_FILE:+ case A10SR_RESET_BQSPI:+ case A10SR_RESET_USB:+ return id + 11;
... but only 5 are handled. What about the other 11? Could you point me
to documentation for this reset controller?
Whoops. Good catch, I will fix this. Remnants of my first implementation
before realizing a switch statement was cleaner.
I looked and apparently we don't publish the System Resource
documentation yet. This is for a CPLD programmed as a system manager so
there is some sharing of reset/enable and status bits.
There were two 8-bit registers but only 5 bits are writable while others
only show status. Bit 2 of the first register and bits 12-15 of the 2nd
register are writable resets.
quoted
+ default:+ return -EINVAL;+ }+}++static int a10sr_reset_update(struct reset_controller_dev *rcdev,+ unsigned long id, bool assert)+{+ struct a10sr_reset *a10r = to_a10sr_rst(rcdev);+ int offset = a10sr_reset_shift(id);+ u8 mask = ALTR_A10SR_REG_BIT_MASK(offset);+ int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset);++ if (id >= rcdev->nr_resets)+ return -EINVAL;
Checking the id is not necessary. The ops are called with rstc->id,
which was checked in of_reset_simple_xlate.
OK. I didn't notice that check. Thanks.
quoted
+ return regmap_update_bits(a10r->regmap, index, mask, assert ? 0 : mask);+}++static int a10sr_reset_assert(struct reset_controller_dev *rcdev,+ unsigned long id)+{+ return a10sr_reset_update(rcdev, id, true);+}++static int a10sr_reset_deassert(struct reset_controller_dev *rcdev,+ unsigned long id)+{+ return a10sr_reset_update(rcdev, id, false);+}++static int a10sr_reset_status(struct reset_controller_dev *rcdev,+ unsigned long id)+{+ int error;+ struct a10sr_reset *a10r = to_a10sr_rst(rcdev);+ int offset = a10sr_reset_shift(id);+ u8 mask = ALTR_A10SR_REG_BIT_MASK(offset);+ int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset);+ unsigned int value;++ if (id >= rcdev->nr_resets)+ return -EINVAL;
Same here. reset_status should never be called with an invalid id.